Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 39 additions & 13 deletions docs/architecture/C1-repair-job-authority.md
Original file line number Diff line number Diff line change
Expand Up @@ -282,16 +282,40 @@ branch **to** the protected parent. The boundary must establish that the effecti
source identity is the authorized repair ref and the effective target identity is
the protected parent ref, reject a symbolic or effective alias that changes that
direction, and fail closed if either effective identity cannot be safely
established.

*Concurrency is not closed by a pre-check.* A resolve-then-check-then-mutate
sequence is **not** an atomic security guarantee: the effective ref or referent
can change between the comparison and the update, so a name observed as an
ordinary repair ref can become symbolic to the protected parent before the
mutation lands. The invariant must be enforced **at the actual mutation/receiving
boundary**, by a mechanism whose semantics prevent an unchecked identity change
between comparison and update — not by an earlier client-side observation this
boundary later trusts.
established. Because this operation performs no ref update to guard, the boundary
that consumes these identities is the change-request/provider creation — or
update — request itself, and the established source and target identities must be
**bound through to that provider request**: the provider must create the request
from exactly the authorized effective source and target. Provider-side resolution
of the supplied ref names is not itself forbidden — a create/update API may have
to resolve the source and target names against its own authoritative repository
state — but it must yield exactly those authorized effective identities: it must
not let re-resolution, ambient repository state, or any substitution cause the
request to be created from, or to consume, a **materially different** effective
source or target than the one authorized. Resolution that preserves the exact
authorized source-to-target relationship conforms; resolution that would consume
a materially different effective identity does not. If that authorized
source-to-target relationship cannot be maintained through to the provider
request — because an effective identity has changed, cannot be safely
re-established, or cannot be shown equivalent to the authorized one at that
boundary — the boundary must fail closed and create no change request.

*Concurrency is not closed by a pre-check.* A resolve-then-check-then-act
sequence is **not** an atomic security guarantee: an effective ref or referent can
change between the comparison and the moment the identity is consumed, so a name
observed as an ordinary repair ref can become symbolic to the protected parent —
or a target can cease to denote it — after the check and before the act. The
invariant must be enforced **at the actual trusted execution boundary that
consumes each identity, not only where a ref is mutated**, by a mechanism whose
semantics prevent an unchecked identity change between the comparison and that
consumption — not by an earlier client-side observation the boundary later trusts.
That consuming boundary differs by operation and the obligation is identical at
each: for `repair.commit` it is the commit mutation boundary, for `repair.push`
the push receiving/mutation boundary, and for `repair.change_request` — which
mutates no ref — the change-request/provider creation boundary at which the source
and target identities are actually consumed. An operation whose authorized
effective-identity relationship cannot be held through to its consuming boundary
must fail closed.

This document states the required invariant, not an implementation: it names no
git command, lock, or transaction mechanism, and it claims no more atomicity than
Expand Down Expand Up @@ -537,9 +561,11 @@ touch, about which ref a commit or push would actually advance, or about the
effective direction of a change request, so a permit must never be read as proof
that repository-level ref identity, the effective mutation target, or the
change-request direction is safe. The trusted execution boundary that acts on a
permit binds the effective target, resolves the effective identity, enforces it at
the mutation/receiving boundary, and fails closed; see *What canonical ref names
do and do not prove* above.
permit binds the effective identity, resolves it, and enforces it at the boundary
that actually consumes that identity — the mutation/receiving boundary for a
`repair.commit` or `repair.push`, and the change-request/provider creation boundary
for a `repair.change_request` — and fails closed; see *What canonical ref names do
and do not prove* above.

### Single use

Expand Down
15 changes: 12 additions & 3 deletions src/domain/repair-job.ts
Original file line number Diff line number Diff line change
Expand Up @@ -529,11 +529,20 @@ function endsWithDotLockSuffix(value: string, start: number, end: number): boole
* effective destination ref for a push. It must **fail closed** — refusing the
* operation — if that effective mutation target is or dereferences to the
* protected parent, if it changes between comparison and update, or if it cannot
* be safely established; a resolve-then-mutate pre-check is not itself atomic, so
* the invariant is enforced at the mutation/receiving boundary. That refusal is
* be safely established; a resolve-then-act pre-check is not itself atomic, so the
* invariant is enforced at the boundary that actually consumes each identity — the
* mutation/receiving boundary for a commit or push, and the
* change-request/provider creation boundary for a change request. That refusal is
* bound to the operand's role rather than being a blanket ban on the protected
* parent's identity: a `repair.change_request` `targetRef` is *required* to reach
* the protected parent ref, and fails closed when it reaches anything else.
* the protected parent ref, and fails closed when it reaches anything else. Because
* that operation mutates no ref, the identity it consumes is bound at its provider
* create/update request: the effective source must remain the authorized repair ref
* and the effective target the protected parent ref through to that request. The
* provider may resolve those ref names at its own boundary, but must not let
* re-resolution or ambient repository state substitute a materially different
* effective identity for either end, and the boundary must fail closed if the
* authorized relationship cannot be maintained or shown equivalent there.
* Nothing here acquires git invocation, filesystem access, a subprocess, or
* network to decide it. See `docs/architecture/C1-repair-job-authority.md`,
* "What canonical ref names do and do not prove".
Expand Down
Loading