feat(devkit): add resumable workspace automation and UI review tooling
Dependency Audit / dependency-audit (push) Successful in 1m45s
Deployment Installer / deployment-installer (push) Successful in 6s
Security Audit / security-audit (push) Successful in 11m30s

Verified with the coordinated workspace changes by devkit full run
2026-09-08T225814-186389-0000-3e3ed7cd (all seven phases passed).
This shared UI pass does not mark the individual module reviews complete.
This commit is contained in:
2026-09-09 02:03:17 +02:00
parent 14b19fbead
commit 2ffdb23f69
67 changed files with 17306 additions and 94 deletions
+151
View File
@@ -0,0 +1,151 @@
import json
import os
from pathlib import Path
import subprocess
import sys
import pytest
sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "tools/devkit"))
from govoplan_devkit.common import atomic_json, read_json, redact, safe_output
from govoplan_devkit.context import build_context
from govoplan_devkit.workspace import (
load_project,
selected_repositories,
git_bytes,
inspect_repository,
Repository,
)
def test_portable_project_rejects_escape_alias_collisions_and_duplicate_json(tmp_path):
config = tmp_path / "project.json"
for repositories in (
[{"name": "repo", "path": "../outside"}],
[
{"name": "repo", "path": "repo", "aliases": ["other"]},
{"name": "other", "path": "other"},
],
):
config.write_text(
json.dumps({"schema_version": 1, "repositories": repositories})
)
with pytest.raises(ValueError):
load_project(tmp_path, config)
config.write_text('{"schema_version":1,"schema_version":2}')
with pytest.raises(ValueError, match="Duplicate"):
read_json(config)
def test_missing_repository_is_error_not_clean(tmp_path):
config = tmp_path / "project.json"
config.write_text(
json.dumps(
{
"schema_version": 1,
"name": "Test",
"repositories": [{"name": "missing", "path": "missing"}],
}
)
)
result = build_context(tmp_path, config, [], True)
assert result["_exit_code"] == 1
assert result["repositories"][0]["errors"]
assert not result["remote_checked"]
def test_unknown_repo_filter_is_not_silently_ignored(tmp_path):
config = tmp_path / "project.json"
config.write_text(
json.dumps(
{"schema_version": 1, "repositories": [{"name": "repo", "path": "repo"}]}
)
)
with pytest.raises(ValueError, match="Unknown"):
selected_repositories(load_project(tmp_path, config), ["typo"])
def test_atomic_output_does_not_chmod_existing_parent(tmp_path):
folder = tmp_path / "public"
folder.mkdir(mode=0o755)
atomic_json(folder / "private.json", {"safe": True})
assert folder.stat().st_mode & 0o777 == 0o755
assert (folder / "private.json").stat().st_mode & 0o777 == 0o600
def test_read_rejects_fifo_and_symlink(tmp_path):
fifo = tmp_path / "fifo"
os.mkfifo(fifo)
with pytest.raises(ValueError, match="regular"):
read_json(fifo)
target = tmp_path / "target.json"
target.write_text("{}")
alias = tmp_path / "alias.json"
alias.symlink_to(target)
with pytest.raises(ValueError, match="symlink"):
read_json(alias)
def test_generic_secret_display_hygiene():
assert "topsecret" not in redact(
"Authorization: Bearer topsecret\nhttps://user:topsecret@example.invalid/"
)
def test_separate_secret_arguments_are_redacted_in_nested_json():
value = {
"stages": [{"argv": ["check", "--token", "hidden-value"]}],
"password": "hidden-password",
}
output = json.dumps(safe_output(value))
assert "hidden-value" not in output and "hidden-password" not in output
@pytest.mark.parametrize(
"name",
[
"GIT_DIR",
"GIT_NAMESPACE",
"GIT_COMMON_DIR",
"GIT_CONFIG_PARAMETERS",
"GIT_AUTHOR_NAME",
],
)
def test_inherited_git_redirects_are_rejected(tmp_path, monkeypatch, name):
monkeypatch.setenv(name, "fixture")
assert inspect_repository(Repository("example", tmp_path))["errors"]
with pytest.raises(ValueError, match="overrides"):
git_bytes(tmp_path, "status")
def test_deeply_nested_json_fails_as_controlled_input_error(tmp_path):
path = tmp_path / "deep.json"
path.write_text("[" * 10000 + "]" * 10000)
with pytest.raises(ValueError, match="nesting"):
read_json(path)
def test_clean_commit_without_upstream_is_still_changed(tmp_path):
subprocess.run(["git", "init", "-q", str(tmp_path)], check=True)
subprocess.run(
[
"git",
"-C",
str(tmp_path),
"-c",
"user.name=Fixture",
"-c",
"user.email=fixture@example.invalid",
"commit",
"--allow-empty",
"-qm",
"fixture",
],
check=True,
)
from govoplan_devkit.workspace import Project
repo = Repository("example", tmp_path)
assert selected_repositories(Project("Example", (repo,), {}), [], changed=True) == [
repo
]