Skip to content

fix(pr-pipeline): hold an unpinned uses: a composite action gains (hardening deferred) #10771

Closed as not planned

Description

@kyle-sexton

Problem

The merge gate's workflow checks in babysit_risk.py read only .github/workflows/*.yml and *.yaml (_WORKFLOWS, is_workflow_path; plugins/source-control/skills/babysit-prs/scripts/babysit_risk.py:807 and :928 on #10743's head). A composite action outside that directory, such as .github/actions/<name>/action.yml, can gain a uses: of a third-party action at an unpinned ref (@main, @v1), a new secret input, or a model leg. No base-against-head check reads it, so the change is held only if its path is on the floor or a review finds it. The same gap applies to secret-exposure-review, agent-surface-review, permission-widening-review and privileged-trigger-review, which read workflow paths only.

The independent security review of #10743 found this. It was pre-existing and left out of that PR's scope.

Evidence

  • _WORKFLOWS = (".github/workflows/*.yml", ".github/workflows/*.yaml"), which _cost_reasons uses to decide whether a file gets the workflow checks.
  • runner-policy and zizmor run in CI over composite actions, but neither feeds the merge gate's person holds.

Proposed fix

Treat .github/actions/**/action.y{,a}ml as workflow text for the net-added uses: checks. Hold for a person when an added uses: is not pinned to a 40-character SHA, and apply the existing secret and model-leg gains there too.

Refs: #10743

Activity

  1. added
    needs-triageNot yet classified. Floor until a type and one priority tier are set.
    on Oct 28, 2026
  2. github-actions commented on Oct 28, 2026

    @github-actions
    Contributor

    Proposed work class: work-class: scoped
    Basis: automated intake triage; the lanes App applied this class.

    Size: Medium
    Complexity: Medium
    Uncertainty: Known
    Flags: none
    Blocked by: none

    Understood: the babysit merge gate's workflow checks (babysit_risk.py) read only .github/workflows/*.y{,a}ml, so a composite action under .github/actions/**/action.y{,a}ml can gain an unpinned uses:, a new secret input or a model leg without a person hold. The proposal is to treat those action files as workflow text for the net-added uses: check (hold unless pinned to a 40-character SHA) and for the existing secret and model-leg checks, and to cover the four sibling review checks too. The scope and approach are clear from the issue. I found no duplicate among the open issues.

    Automated triage, applied by the lanes App.

  3. added
    priority: mediumReal value, no hard deadline; normal backlog flow.
    and removed
    needs-triageNot yet classified. Floor until a type and one priority tier are set.
    on Oct 28, 2026
  4. added
    status: readyTriaged, unblocked, and fully specified; eligible to pick up.
    work-class: scopedA briefed fix or small feature; blast radius bounded by the brief, tests exist.
    status: confirmedA maintainer confirmed the item is real and in scope; ready to be worked.
    and removed
    status: readyTriaged, unblocked, and fully specified; eligible to pick up.
    on Oct 28, 2026
  5. melodic-automation-lanes commented on Oct 28, 2026

    @melodic-automation-lanes
    Contributor

    Not admitted to the issue lane: no trusted-human acceptance criteria: a listed human must put the confirmed - [ ] criteria in the body or post them as their own comment, or, on an issue a listed human filed, intake's newest refinement comment must hold them unedited. Admission takes the issue once each of those is met, when intake triages it again (.github/actions/resolve-config/admission-rules.json).

  6. melodic-automation-lanes commented on Oct 28, 2026

    @melodic-automation-lanes
    Contributor

    The latest triage verdict holds nothing: admission moved the issue to status: confirmed; its comment says why.

  7. melodic-automation-lanes commented on Oct 28, 2026

    @melodic-automation-lanes
    Contributor

    Refinement. A read-only run explored this repository, searched its issues and pull requests, and read the allowed docs to draft what follows. On an issue a listed human filed, it counts as the issue's spec once posted, while unedited; it is still model text, so check it.

    Intended outcome: Composite action files under .github/actions/**/action.y{,a}ml get the same net-added uses:, secret and model-leg checks as workflow files, and an added uses: not pinned to a 40-character SHA holds for a person.

    Related work

    Open questions

    1. Should this wait for #​10743 to merge? The base checkout has no unpinned-uses check and no permission-widening-review or privileged-trigger-review codes in babysit_risk.py, so those checks must come from #​10743.
      RECOMMENDED: Yes. Make #​10743 a dependency and implement against its merged code, adding the action globs to the shared workflow-path predicate. Basis: plugins/source-control/skills/babysit-prs/scripts/babysit_risk.py:749
    2. Which checks are in scope? The body names the unpinned uses:, secret and model-leg checks, and also says the permission-widening and privileged-trigger reviews read workflow paths only.
      RECOMMENDED: Cover the unpinned uses:, secret and model-leg checks. Include permission-widening and privileged-trigger only if they exist after #​10743, and only where the key is meaningful in a composite action. Basis: judgment
    3. Should the cost-only checks (runs-on, cron, timeouts, retention, new runners) also apply to action files, or stay workflow-only?
      RECOMMENDED: Keep them workflow-only. Composite actions have no runs-on, cron or job timeouts, and _cost_reasons at babysit_risk.py:1007 and :1025 applies all of them under one workflow flag, so the change must split that flag. Basis: plugins/source-control/skills/babysit-prs/scripts/babysit_risk.py:1025

    Sources read

    • plugins/source-control/skills/babysit-prs/scripts/babysit_risk.py:760: _WORKFLOWS is only .github/workflows/*.yml and *.yaml
    • plugins/source-control/skills/babysit-prs/scripts/babysit_risk.py:881: is_workflow_path matches only _WORKFLOWS
    • plugins/source-control/skills/babysit-prs/scripts/babysit_risk.py:1007: _cost_reasons gates secret and model-leg checks on is_workflow_path
    • plugins/source-control/skills/babysit-prs/scripts/babysit_risk.py:935: _net_added helper compares matches gained over removed lines
    • plugins/source-control/skills/babysit-prs/scripts/babysit_risk.py:749: only secret-exposure-review and agent-surface-review codes exist in the base

    To answer, post a comment that starts with this line:

    **Decision recorded.** <answer>
    

    Automated refinement by the lanes App. Answer with a comment whose first line is **Decision recorded.**.

  8. changed the title [-]fix(pr-pipeline): hold an unpinned uses: a composite action gains[/-] [+]fix(pr-pipeline): hold an unpinned uses: a composite action gains (hardening deferred)[/+] on Oct 30, 2026
  9. kyle-sexton commented on Oct 30, 2026

    @kyle-sexton
    MemberAuthor

    Decision recorded. Hardening deferred, closed as not planned under owner standing direction §10: "Phase: maximum throughput until open issues and open PRs both reach 0. Hardening (re-adding holds, pins, reviews) is deferred to after that, as configuration edits."

    This issue adds a hold, a pin or a check that guards against our own actors, and none of its gaps can leak a token or secret, compromise the owner accounts or bill. §10 counts only those as a §3 boundary. Secret-leak scanning (gitleaks) stays on, as do both review lanes and ci-status (owner Q15).

    Reopen trigger: open issues = 0 and open PRs = 0. The hardening pass finds this with is:issue is:closed reason:"not planned" in:title "hardening deferred".

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    priority: mediumReal value, no hard deadline; normal backlog flow.status: confirmedA maintainer confirmed the item is real and in scope; ready to be worked.status: needs-decisionAwaiting a human or maintainer judgment call.work-class: scopedA briefed fix or small feature; blast radius bounded by the brief, tests exist.

    Type

    Fields

    No fields configured for Bug.

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions