7e19079b5cc6b029aed729945c91e9edc5a1c721
6
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
03b434a0b6 |
fix(guard): derive base ref from configured upstream, not the remote-HEAD cache
Remediates the REQUEST_CHANGES verdict (review 658) at head |
||
|
|
2d5d5c9d17 |
fix(guard): derive cross-repository target base ref
Cross-repository mutation gating assumed the tracking base ref was
prgs/master, and parity reporting independently assumed origin/master.
A namespace bound to any other repository -- for example remote MDCPS on
integration branch dev -- could not prove base equivalence, so every
gated mutation failed closed with no reachable remedy. The two modules
also disagreed with each other, so at most one could be right for any
given repository.
Derive the target instead of assuming it. canonical_repository_root
already discovered the correct remote while resolving repository
identity and then discarded its name; it now returns that name with its
exact configured case preserved, and resolve_target_base_ref() builds
refs/remotes/<remote>/<branch> from it. The integration branch comes
from refs/remotes/<remote>/HEAD -- git's own record of the remote's
default branch -- so no new configuration field is required. Only when
a remote publishes no such default does it fall back to exactly one
present integration-branch candidate.
Resolution fails closed with a machine-checkable reason_code when
identity is unprovable, when distinct remotes claim different
repositories, when several candidate branches exist with no recorded
default, or when no candidate exists. It never invents a branch, writes
a ref, or falls back to another repository's base.
Both the mutation guard and the parity report now consume that one
resolved target, so they cannot disagree again. Root-checkout
contamination names the ref it actually compared rather than a literal
prgs/master the target repository may not have.
Fixes an observable defect in this repository: refs/remotes/origin/master
survives as an orphan ref from a removed remote, so parity reported the
target stale against a dead commit while reporting its identity as
underivable.
PRGS behaviour is unchanged -- prgs/master still resolves via the
recorded remote HEAD to the same SHA, and an explicit remote_refs
override keeps the historical probe path verbatim.
Tests: 24 new hermetic regression tests covering PRGS prgs/master,
MDCPS/dev, no origin remote, exact remote-name case, equal/behind/
divergent targets, missing remote or ref, ambiguous remote and branch
resolution, gate/report agreement, and every affected production
caller. Full suite 6191 passed / 28 failed, byte-identical failure set
to the baseline at
|
||
|
|
34968475c7 |
fix(runtime): reject unsupported repository-authority modes (#973 B10)
assess_canonical_repository_root declared a public `mode` keyword defaulting to "validation" and documented exactly two supported values, but never checked the argument against an allowlist. Both dispatch points were permissive: * the configured-root path tested `mode == "derivation"` and routed every other value into a catch-all `else`, so an unsupported mode silently received validation semantics; and * the single-repository default path tested `mode == "validation"`, so an unsupported mode skipped the identity comparison entirely and was strictly weaker than validation, not an alias of it. Measured at the previous head: mode="invalid_mode" with require_binding=True and matching expected/observed identities returned proven=True, block=False with no reasons; on the unconfigured path an unsupported mode returned proven=True where mode="validation" returned proven=False for identical inputs. Empty string and None behaved like any other unsupported value, and no assessment ever emitted a mode-specific rejection. Add an explicit two-value allowlist (SUPPORTED_MODES) and refuse every other explicitly supplied value — unknown strings, misspellings, case and whitespace variants, the empty string, None, and non-strings — as the first act of the function, before any candidate-root existence check, path or symlink resolution, git top-level discovery, remote-URL or repository-identity discovery, and before any expected-versus-observed comparison or validation/derivation behaviour. The refusal reports proven=False, block=True, a mode-specific reason naming the offending value, and reason_code=DENY_UNKNOWN_MODE, following the existing webui.sanctioned_restart.DENY_UNKNOWN_MODE convention. No repository identity is resolved through a refused mode: resolved_slug and canonical_repo_root are both None. Omission continues to select validation, so the documented default is unchanged. Unsupported modes are refused rather than normalized onto a supported mode. No mode is exposed through MCP request parameters, environment variables, repository configuration, session input, or any public reviewer, merger, issue, PR or lease API; the only production call sites remain an omitted mode (validation) and the hardcoded "derivation" literal. resolve_namespace_mutation_context keeps the install checkout as the canonical root when an assessment resolves none, so a refused mode cannot bind a root derived through an undefined mode while roots_aligned and the carried assessment stay fail-closed. Regressions in tests/test_issue_973_b10_mode_contract.py cover invalid modes with missing, matching and conflicting identities, empty string, explicit None, representative non-strings, misspellings and whitespace variants, omission defaulting to validation, explicit validation and derivation behaviour, the single-repository default path differential, rejection ordering (both spied and mock-free), the absence of any request/environment/configuration injection surface, and fail-closed reviewer, merger, mutation-context and final mutation-authorization behaviour through the production paths. Closes #973 Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]> |
||
|
|
a6c7d1491e | fix(runtime): fix identity derivation disarming in canonical root guard (Closes #973) | ||
|
|
9d96cf4cfa | fix(runtime): derive expected repository identity independently of configured root (Closes #973) | ||
|
|
0d8a2c2b1d |
feat(mcp): immutable canonical_repository_root for cross-repo namespaces (Closes #706)
The MCP server derived the canonical repository root from the install checkout the server script lives in (PROJECT_ROOT), so any namespace that ran the server against an external repository (e.g. eagenda-author, or the mcp-control-plane reviewer/merger namespaces) failed every mutation: the branches-only / worktree-membership guards (#274) compared the task workspace against the Gitea-Tools .git directory it can never belong to. Separate the two concepts: - PROJECT_ROOT stays the immutable code/install root. - A new, optional, namespace-scoped canonical_repository_root binds the session to the working root of the target repository. Implementation: - canonical_repository_root.py: resolve the binding from profile/env (GITEA_CANONICAL_REPOSITORY_ROOT overrides the profile field), validate existence + git identity, fail closed on missing/conflicting/forged bindings. Preserves the single-repo default when unconfigured. - session_context_binding.py: pin canonical_repository_root into the immutable #714 session context; drift fails closed. - namespace_workspace_binding.py: route the configured target root through resolve_namespace_mutation_context so #274 / membership guards evaluate against the target repository. - gitea_mcp_server.py: seed + enforce the binding in the mutation preflight (both purity-order and FORCE_PRODUCTION_GUARDS paths); validate repository identity and git common-directory membership. - gitea_config.py: validate the optional absolute-path profile field. - gitea_auth.py: surface the config-sourced field through get_profile. No weakening of root-checkout, remote/repository, or anti-stomp guards; the single-repo Gitea-Tools path is unchanged. Tests: two distinct real git repositories/worktrees prove cross-repository bindings resolve, enforce membership, and fail closed on forged/conflicting identity and simultaneous prgs/mdcps isolation. Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]> |