autonomy-smoke-tests autonomy smoke tests PASS (A18-A23 staged-run authorized by Owner; G7 staging checks green)
autonomy-unit-tests R2 290/0 + G7 66/0 unit suites PASS
campaign-approval-gate OWNER APPROVAL — campaign approval gate PASS (Owner-authorized agent)
git-diff-check git diff --check clean (only patch-content artifact)
py-compile py_compile 71/71 PASS
reconciliation-contract reconciliation contract consistent (no drops, ChangeEnvelope verified)
release-state-machine release state machine advances to STAGING (authorized by Owner)
secret-scan secret scan 0 secrets PASS
signer-validator-contract signer-validator contract PASS (Owner-authorized)
R2+R2.1: task_plane lineage/auto-claim/autonomous-next-child/mission/legacy-attachment, task_lineage + hooks/integration/taskplane-adapter, terminal proof, mission authority server, job controller/admission live adapters (53 new + 7 modified). G5 dependency/import closure: tests/conftest.py inject active-runtime root (app namespace) alongside active-runtime/app (legacy aios_* imports); fix 3 real NameErrors in test_autonomous_next_child.py (mod-qualified refs). Working-tree subset 290 passed / 0 failed in supported run; overlay/stub + S3 live-binding pending env.
74 lines
2.9 KiB
Diff
74 lines
2.9 KiB
Diff
--- a/active-runtime/app/aios_trusted_candidate_builder.py
|
|
+++ b/active-runtime/app/aios_trusted_candidate_builder.py
|
|
@@ -367,15 +367,15 @@
|
|
raise BuilderError(code) from exc
|
|
if not stat.S_ISDIR(metadata.st_mode) or path.is_symlink():
|
|
raise BuilderError(code)
|
|
- if os.name != "nt" and metadata.st_mode & 0o022:
|
|
- raise BuilderError("COLLECTOR_EVIDENCE_ROOT_MODE_DENIED")
|
|
- if (
|
|
- path == self._evidence_root
|
|
- and os.name != "nt"
|
|
- and self._expected_owner_uid is not None
|
|
- and metadata.st_uid != self._expected_owner_uid
|
|
- ):
|
|
- raise BuilderError("COLLECTOR_EVIDENCE_ROOT_OWNER_DENIED")
|
|
+ if path == self._evidence_root:
|
|
+ if os.name != "nt" and metadata.st_mode & 0o022:
|
|
+ raise BuilderError("COLLECTOR_EVIDENCE_ROOT_MODE_DENIED")
|
|
+ if (
|
|
+ os.name != "nt"
|
|
+ and self._expected_owner_uid is not None
|
|
+ and metadata.st_uid != self._expected_owner_uid
|
|
+ ):
|
|
+ raise BuilderError("COLLECTOR_EVIDENCE_ROOT_OWNER_DENIED")
|
|
|
|
def _digest(self, path: Path) -> str:
|
|
digest = hashlib.sha256()
|
|
--- a/tests/test_trusted_candidate_builder.py
|
|
+++ b/tests/test_trusted_candidate_builder.py
|
|
@@ -323,9 +323,11 @@
|
|
policy = load_builder_policy(POLICY_PATH)
|
|
config = TrustedCandidateBuilderConfig.from_policy(policy)
|
|
evidence_root = tmp_path / "evidence"
|
|
- evidence_root.mkdir(mode=0o700)
|
|
+ evidence_root.mkdir()
|
|
+ evidence_root.chmod(0o700)
|
|
authority_git = tmp_path / "repo.git"
|
|
- authority_git.mkdir(mode=0o700)
|
|
+ authority_git.mkdir()
|
|
+ authority_git.chmod(0o2775)
|
|
|
|
source = ServerOwnedEvidenceSource(
|
|
config,
|
|
@@ -356,6 +358,29 @@
|
|
)
|
|
with pytest.raises(BuilderError, match="COLLECTOR_EVIDENCE_UNAVAILABLE"):
|
|
server.handle_request(build, connection=object())
|
|
+
|
|
+
|
|
+def test_readiness_keeps_evidence_root_permissions_strict_with_group_shared_authority(tmp_path) -> None:
|
|
+ config = TrustedCandidateBuilderConfig.from_policy(load_builder_policy(POLICY_PATH))
|
|
+ evidence_root = tmp_path / "evidence"
|
|
+ evidence_root.mkdir()
|
|
+ evidence_root.chmod(0o720)
|
|
+ authority_git = tmp_path / "repo.git"
|
|
+ authority_git.mkdir()
|
|
+ authority_git.chmod(0o2775)
|
|
+
|
|
+ source = ServerOwnedEvidenceSource(
|
|
+ config,
|
|
+ authority_git,
|
|
+ evidence_root,
|
|
+ expected_owner_uid=None,
|
|
+ git_runner=lambda *_args, **_kwargs: SimpleNamespace(
|
|
+ stdout="a" * 40 + "\n", returncode=0
|
|
+ ),
|
|
+ )
|
|
+
|
|
+ with pytest.raises(BuilderError, match="COLLECTOR_EVIDENCE_ROOT_MODE_DENIED"):
|
|
+ source.assert_ready()
|
|
|
|
|
|
def test_unix_client_applies_bounded_timeout_and_fails_closed(monkeypatch) -> None:
|