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
2 changes: 1 addition & 1 deletion .github/actions/dotnet-publish-default/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ runs:
# GitHub-release asset, uploaded under the release-asset-<branch>-<target> pattern the github-release job collects.
- name: Upload release asset step
if: ${{ inputs.smoke != 'true' }}
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
with:
name: release-asset-${{ inputs.branch }}-dotnet-publish
path: ${{ steps.zip.outputs.asset-path }}
Expand Down
4 changes: 2 additions & 2 deletions .github/actions/nuget-build-default/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ runs:
# It runs inside the hub task's job, so an adopter's registry sees this hub in the job_workflow_ref claim and rejects the push.
- name: Upload build artifacts step
if: ${{ inputs.smoke != 'true' }}
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
with:
name: nuget-build-${{ inputs.branch }}
path: |
Expand All @@ -89,7 +89,7 @@ runs:
# GitHub-release asset, uploaded under the release-asset-<branch>-<target> pattern the github-release job collects.
- name: Upload release asset step
if: ${{ inputs.smoke != 'true' }}
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
with:
name: release-asset-${{ inputs.branch }}-nuget
path: ${{ runner.temp }}/nuget.7z
Expand Down
4 changes: 2 additions & 2 deletions .github/actions/pypi-build-default/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ runs:
exit 1

- name: Setup uv step
uses: astral-sh/setup-uv@c771a70e6277c0a99b617c7a806ffedaca235ff9 # v9.0.0
uses: astral-sh/setup-uv@1c37ad07a6a961277cf70c0d37d6f313000f5884 # v10.3.0
with:
version: ${{ inputs.uv-version }}
enable-cache: true
Expand Down Expand Up @@ -115,7 +115,7 @@ runs:
# It runs inside the hub task's job, so an adopter's registry sees this hub in the job_workflow_ref claim and rejects the push.
- name: Upload build artifacts step
if: ${{ inputs.smoke != 'true' }}
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
with:
name: pypi-build-${{ inputs.branch }}
path: ${{ inputs.project-dir }}/dist/*
Expand Down
2 changes: 1 addition & 1 deletion .github/actions/validate/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ runs:
python3 spec/validate.py

- name: Setup uv step
uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v8.1.0
uses: astral-sh/setup-uv@1c37ad07a6a961277cf70c0d37d6f313000f5884 # v10.3.0
with:
python-version: "3.13"

Expand Down
2 changes: 1 addition & 1 deletion catalog/snippets/workflows/test-pull-request-smoke.yml
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ jobs:
smoke-build:
name: Smoke build job
needs: [changes]
if: needs.changes.outputs.release == 'true'
if: github.event_name == 'workflow_dispatch' || needs.changes.outputs.release == 'true'
uses: ptr727/ProjectTemplate/.github/workflows/build-release-task.yml@6c88850128629bb449fd73c7fbf82968c6cd1557 # 2.0.587
permissions:
contents: read
Expand Down
2 changes: 1 addition & 1 deletion docs/reusable-workflows.md
Original file line number Diff line number Diff line change
Expand Up @@ -355,7 +355,7 @@ jobs:
smoke-build:
name: Smoke build job
needs: [changes]
if: needs.changes.outputs.release == 'true'
if: github.event_name == 'workflow_dispatch' || needs.changes.outputs.release == 'true'
uses: ptr727/ProjectTemplate/.github/workflows/build-release-task.yml@6c88850128629bb449fd73c7fbf82968c6cd1557 # 2.0.587
permissions:
contents: read
Expand Down
15 changes: 12 additions & 3 deletions host-setup/agent-safety/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,10 +54,19 @@ text says, because the harm it covers was never in the text.
precision-over-recall stance every requirement but 4 takes. A write is recognized by its command
and subcommand as gh's own parser finds them, past the flags before each. So a repo flag before
the command or between `pr` and its subcommand still names the target. The target is also the
`R` in a short-option cluster such as `-dR`, and a `GH_REPO` value that reaches the gh word. One
`R` in a short-option cluster such as `-dR`, and a `GH_REPO` value that reaches the gh word,
the one in the environment the session was launched with included. A repository named by a
write's positional argument is one too, as in a pull request or issue URL, and so is the
repository `gh repo edit` or `gh issue transfer` takes. On a `gh api` write, an owner named by an
`orgs/`, `users/`, or `user/...` path counts, as in `orgs/<owner>/...` or `user/starred/<owner>/<repo>`. A
`[HOST/]OWNER/REPO` value is read by its middle owner as well as by its first part. A gh write
run through a run-time command word, as in `G=gh; $G pr comment ...`, is read as one. One
exception departs from that stance. A write whose repository owner is a run-time word fails
closed, since it leaves nothing to compare. That covers `--repo "$T"`, `GH_REPO="$T"`, and
`repos/$O/...`, while `--repo "example/$R"` names its owner and is compared as usual.
closed, since it leaves nothing to compare. That covers `--repo "$T"`, `GH_REPO="$T"`,
`repos/$O/...`, a run-time repository positional, and a `gh api` write whose endpoint opens
with a run-time word. It also covers a run-time word before gh's command that may hold a repo
flag, as in `gh "$R" pr comment`. A `--repo "example/$R"` names its owner and is compared as
usual.
4. **A git operation that would only succeed by bypassing an active branch rule is denied**: a
direct push to a branch whose rules require a pull request, a force-push where history is
protected, a delete where deletion is blocked, or an explicit-bypass flag (`--admin` on a merge,
Expand Down
2 changes: 1 addition & 1 deletion host-setup/agent-safety/claude/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ Every other key in the file is left as it stands, `permissions.allow` and the re
- **Per-machine.** `~/.claude/` does not travel, so run the installer on each box. This is the rollout that [#365][issue-365] tracks.
- **Precision over recall for the write footguns.** The hook denies the specific dangerous write shapes with high confidence rather than gating every write, so it is written to avoid blocking legitimate work -- a known false-positive shape is a parser defect to fix, not an accepted cost. The exception is a write whose repository owner is a run-time word, denied because it leaves nothing to compare. A shape it does not catch still falls under the behavioral rules.
- **The branch-bypass rule fails closed.** Unlike the write-footgun rules, a push to `main`/`master`/`develop` is denied even when its rules cannot be determined (the API is unreachable, or the checkout's origin cannot be resolved to query them), because the harm there is a silent success under the maintainer's admin bypass. The rule reads each branch's live rules, so it adapts to every repo (a code-style `develop` denies, a config-style `develop` allows) with no per-repo configuration, and hands the exact command to the maintainer to run when a bypass is genuinely intended.
- **Opaque targets are unseen.** The hook cannot see the repository behind a GraphQL node id, which is exactly why rule 2 blocks a *literal* id at all, since a captured `$variable` is trusted. Likewise, the cross-origin check only runs when an `origin` can be resolved and the write names an explicit `-R`/`repos/<owner>/<repo>`/`GH_REPO` target. A write from a non-git directory, or one whose target is only a node id, is evaluated by rules 1 and 2 alone.
- **Opaque targets are unseen.** The hook cannot see the repository behind a GraphQL node id, which is exactly why rule 2 blocks a *literal* id at all, since a captured `$variable` is trusted. Likewise, the cross-origin check only runs when an `origin` can be resolved and the write names an explicit target, such as `-R`, `repos/<owner>/<repo>`, a `GH_REPO` value, or a pull request URL. A write from a non-git directory, or one whose target is only a node id, is evaluated by rules 1 and 2 alone. The hook reads an inherited `GH_REPO` from its own environment, the one the session was launched with. A value a Bash tool call gets some other way, such as from a shell profile it sources, is not seen. An inherited value is read beside any `export` in the command, since the hook cannot tell whether that export runs. To write elsewhere, override it with a prefix, as in `GH_REPO=<owner>/<repo> gh ...`, or with `-R`.
- **A write or a wait inside a script file is unseen, so never put either in a script to run it.** The hook reads the command the agent runs, which for `bash deploy.sh` is that one string. A `git push` or a `gh` mutation inside the script therefore reaches the server unparsed. An unbounded wait inside that same script is equally unseen, and worse in one way. A denied write fails loudly. A wait the guard never saw runs until something ends it, which is one of the leaks the SessionEnd sweep exists to find afterwards. This is the widest hole in the kit, and an agent opens it by accident. Collecting fifteen repetitive pushes into a loop looks like tidiness, and so does moving a poll into a script to keep a tool call short. Neither looks like disabling a guard. Issue each write and each wait as its own command. A script that only reads, computes, or prepares local commits is fine, because the boundary is the write and the wait rather than the script.
- **Not a credential control.** A fine-grained PAT limited to owned repositories is a separate, stronger structural guard (a hard `403` on any non-owned repo) and is left to per-machine credential setup, out of this kit.
- **Rule 6's ref-checkout and `--ff-only` exemptions are deliberate, not a gap.** The #1073 incident's own literal commands (an unforced `git checkout main`, then `git pull --ff-only`) are exactly this shape, so this rule does not deny the incident's own commands specifically. Denying them would also break the documented base-clone cleanup step in the `repo-worktree` skill, which needs precisely those two. The concurrent-access hazard those commands still carry (switching HEAD, or fast-forwarding, in a checkout another task might be relying on) is not decidable from the command text alone, so it stays the prose rule's job. A non-force flag alongside the ref, such as `--detach`, is exempt too, not only a strictly zero-flags invocation -- git's own overwrite-refusal on a dirty tracked file is unaffected by it, verified live.
Expand Down
Loading
Loading