Skip to content

A scope that could not be evaluated stands the destination guard down #120

Description

@HackingGate

scope = "public-target" is the one predicate that asks somebody else. A forge
that cannot be asked answers nothing, and that answer is currently spelled the
same way as "the policy decided these checks do not apply here".

Repro

A shim scoped public-target and a prevent-unowned-target rule behind it, in a
tree with no remote (or with gh unauthenticated, or offline):

faux issue create --repo other-owner/their-repo -b "An ordinary sentence."
# stderr: uphold shim: no target could be resolved, ... This is not a pass.
# exit 0, the command runs, the issue is opened on somebody else's repository

REFERENCE.md line 1085 and the doc comment on guard::target_refusal
(src/guard/mod.rs:298) both promise exit 2 for a destination that could not be
resolved. Neither is reached: the caller never gets that far.

Cause

Scope::PublicTarget in Shim::scope_holds (src/shim.rs:822) returns
Ok(false) twice: for "no target resolvable" (src/shim.rs:838) and for "the
forge would not say" (src/shim.rs:848). false is "out of scope", so the caller
at src/shim.rs:1953 skips the rule, and guard::target_refusal (which does hold
the exit-2 answer) is never called. The stand-down happens exactly where the
lookup failed, which is the invocation that most needs asking about.

Fix

Three answers rather than two: Holds / DoesNotHold / CouldNotTell. On
CouldNotTell, refuse before exec with exit 2, naming what could not be asked.

A new per-[[shim]] field unresolved = "run" opts back into the old
behaviour, for a workspace whose forge is routinely unreachable; the default is
"refuse". Under "run" the stderr line stays and says the command ran with
nothing checked.

Document it in REFERENCE.md beside the refuse_unknown table, which draws the
same distinction for the same forge lookup, and in the shim's own section. Add
it to the config validation as well: public-target is the only scope that can
answer "could not tell", so the field beside any other scope is read by nothing,
which is the shape [[shim.verbs]] for an unmatched verb is already refused for.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions