Skip to content

feat(workflows): add thin caller for the issue-triage-label reusable - #850

Merged
kyle-sexton merged 2 commits into
mainfrom
ci/506-triage-label-caller
Jul 21, 2026
Merged

feat(workflows): add thin caller for the issue-triage-label reusable#850
kyle-sexton merged 2 commits into
mainfrom
ci/506-triage-label-caller

Conversation

@kyle-sexton

Copy link
Copy Markdown
Contributor

Closes #506

Summary

Adds .github/workflows/issue-triage-label.yml, a thin caller invoking
ci-workflows' issue-triage-label reusable workflow (workflow_call) on
issues: opened/reopened. Applies the existing priority: needs-triage
label when an issue carries no priority:* label; leaves issues filed with
an explicit tier untouched. Non-gating.

  • Pinned by merged SHA c5e729c0af0e55ffed4675ec85c1b57356fef79e (ci-workflows
    PR build: Bump the npm-minor-patch group across 1 directory with 2 updates #191), matching this repo's existing SHA-pin convention
    (pr-issue-linkage.yml, do-not-merge.yml, link-check.yml).
  • Uses the reusable's defaults for label (priority: needs-triage) and
    label-prefix (priority:) — both already match this repo's taxonomy, so
    no overrides needed. runner: ubuntu-24.04 passed explicitly per sibling
    caller convention.
  • Verified live: priority: needs-triage exists in this repo's label set
    (gh label list), so the reusable's fail-closed missing-label guard will
    not trip.
  • Locally verified clean: actionlint, zizmor --persona=pedantic (0
    findings after adding an explanatory comment on the issues: write grant),
    typos.

Related

melodic-software/ci-workflows#191 (merged 2026-07-21T10:06:31Z) implements the
reusable workflow this caller invokes, carrying the settled mechanism from
#506's 2026-07-20 Class-B research-resolution comment and the tower decision
comment confirming this thin-caller shape.

Test plan

  • actionlint .github/workflows/issue-triage-label.yml
  • zizmor --persona=pedantic .github/workflows/issue-triage-label.yml (0 findings)
  • typos .github/workflows/issue-triage-label.yml
  • gh label list confirms priority: needs-triage exists live in this repo

Applies priority: needs-triage to issues opened/reopened without a
priority tier, via ci-workflows' issue-triage-label reusable workflow.

Closes #506
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, you can upgrade your account or add credits to your account and enable them for code reviews in your settings.

@claude

claude Bot commented Jul 21, 2026

Copy link
Copy Markdown
Contributor

Claude finished @kyle-sexton's task in 1m 0s —— View job


PR Review: feat(workflows): add thin caller for the issue-triage-label reusable

  • Gather context and read changed files
  • Review workflow file for correctness and security
  • Verify SHA pin convention alignment
  • Final summary

Review

This is a clean, minimal thin-caller workflow. No blocking issues found.

What was checked:

  • SHA pin format against siblings (do-not-merge.yml, pr-issue-linkage.yml, link-check.yml)
  • Permission structure (workflow-level vs job-level scoping)
  • Trigger and runner convention
  • Security posture

SHA pin format — consistent with siblings that omit a description suffix after the date:

# pr-issue-linkage.yml  → @d7734df…  # d7734df 2026-07-20
# link-check.yml        → @90f1c54…  # 90f1c54 2026-07-18
# new file              → @c5e729c…  # c5e729c 2026-07-21  ✓

Permission structurepermissions: {} at workflow scope with issues: write scoped to the job, matching the pr-issue-linkage.yml shape. The explanatory comment on the grant is present. ✓

Runnerrunner: ubuntu-24.04 passed explicitly, consistent with all four sibling callers. ✓

Concurrency block — absent, which differs from the pull_request_target sibling callers. That's correct: those need it to cancel stale runs on rapid pushes; issues: opened/reopened events are discrete per issue — no stacking concern. ✓

Reusable defaults not overriddenlabel and label-prefix use the reusable's defaults, which the PR confirms already match this repo's label taxonomy. ✓

Security — supply-chain hardened (SHA pin, not tag/ref), no secrets surfaced, no expression-injected inputs (runner is a literal string), zizmor --persona=pedantic at 0 findings per PR description. ✓


One minor observation (non-blocking): the header comment references the settled mechanism from #506, but doesn't mention ci-workflows PR #191 (the specific merged source of the SHA). The sibling callers don't inline cross-repo PR references either, so this is consistent — just noting it for anyone who wants to trace the SHA origin later without reading the PR body.

Overall: LGTM. The file is correct, minimal, and follows all established conventions.

@claude

claude Bot commented Jul 21, 2026

Copy link
Copy Markdown
Contributor

Claude finished @kyle-sexton's task in 1m 10s —— View job


Security Review

  • Gather context
  • Read changed workflow file
  • Analyze for dangerous GHA patterns
  • Analyze permissions grants
  • Analyze supply-chain / pin risk
  • Check for injection surfaces
  • Post findings

No security issues found. The thin caller is well-constructed across every risk dimension checked:

Trigger (issues: opened/reopened): The issues event does not carry elevated token permissions for untrusted fork code (unlike pull_request_target or workflow_run). No OIDC or secret exposure risk from the trigger itself.

Permissions (L15–19): Top-level permissions: {} denies all permissions by default — the correct baseline. The job scopes up only to issues: write, the minimum required for the reusable to read and apply labels. contents, pull-requests, and all other permissions remain denied. No secrets: inherit is present, so zero secrets are forwarded to the called workflow.

Injection surfaces (L20–23): There are no run: blocks anywhere in this file, eliminating script-injection risk entirely. The only with: input is the static literal ubuntu-24.04 — no ${{ github.event.* }} or other context variable interpolation that could carry attacker-controlled issue title/body into a shell.

Supply-chain / pin (L21): The reusable is pinned to a full 40-character commit SHA (c5e729c0af0e55ffed4675ec85c1b57356fef79e), not a mutable branch or tag ref. This is the gold standard; the referenced code is immutable. The target is the same-org melodic-software/ci-workflows, not an external/third-party action, which further reduces trust-delegation risk.

Context forwarding: The caller passes no issue-event context (title, body, labels) into the reusable via with:. The only passed value is the static runner string. This is correct; any handling of event payload context is entirely inside the reusable (out of scope for this PR).

Consistency with repo convention: The pattern (permissions: {} top-level, narrow job-level grant, SHA pin with date comment, no secrets: inherit) is identical to the sibling callers (pr-issue-linkage.yml, do-not-merge.yml, link-check.yml).

@kyle-sexton

Copy link
Copy Markdown
Contributor Author

Blocked on CI: the `Runner policy` check fails because `.github/standards/runner-policy/policy.json` (a managed, standards-synced file per `standards/distribution/sync-manifest.yml` — never edited directly downstream) has no reviewed `approvedReusableWorkflowContracts` entry for this new reusable at any SHA:

```
.github/workflows/issue-triage-label.yml#issue-triage-label: runner-target-contract: the reusable workflow path@SHA has no reviewed runner-input contract
```

Filed the upstream request: melodic-software/standards#235. This PR will re-green once that contract lands and syncs down via the automated "chore: sync standards components" PR — no local workaround exists (or should exist) for a synced security policy file.

@kyle-sexton

Copy link
Copy Markdown
Contributor Author

Staged the fix: melodic-software/standards#236 registers the reviewed runner-policy contract for `issue-triage-label.yml@c5e729c` (Closes melodic-software/standards#235). Locally verified there (227/227 `test:runner-policy`, `lint:runner-policy` passing, `lint:md`, `lint:hooks`).

Not merging that PR — runner-policy is a hand-reviewed supply-chain allowlist, so it goes through operator review/merge rather than autonomous merge. This PR will re-green once #236 merges and syncs down here via the standard "chore: sync standards components" automation.

kyle-sexton added a commit to melodic-software/standards that referenced this pull request Jul 21, 2026
…ontract (#236)

Closes #235

## Summary
Registers ci-workflows' `issue-triage-label` reusable workflow as a
reviewed `runner-input` contract in
`components/runner-policy/policy.json`,
pinned to its merged SHA `c5e729c0af0e55ffed4675ec85c1b57356fef79e`:

```json
"melodic-software/ci-workflows/.github/workflows/issue-triage-label.yml@c5e729c0af0e55ffed4675ec85c1b57356fef79e": {
  "routing": "runner-input",
  "runnerInput": "runner",
  "allowedInputs": ["runner", "label", "label-prefix"],
  "allowedSecrets": {},
  "allowedCallerPermissions": { "issues": "write" }
}
```

- `allowedInputs` covers the reusable's full `workflow_call.inputs`
surface
  (`runner`, `label`, `label-prefix`) — a caller may pass any subset.
- `allowedSecrets: {}` — the reusable takes no secrets.
- `allowedCallerPermissions: { issues: write }` — the reusable's job
needs
exactly `issues: write` to read and add labels; no `contents` (no
checkout).
- No `selectorResultInput` — the reusable has no chained-selector
  (`prerequisite-result`-style) input.

Locally verified: `npm run test:runner-policy` (227/227 passing),
`npm run lint:runner-policy` ("Runner policy passed."), `npm run
lint:md`,
`npm run lint:hooks`, plus `lefthook`'s pre-commit gate (typos,
gitleaks,
editorconfig, biome) on commit.

## Related
- melodic-software/ci-workflows#191 — the reusable workflow, merged.
- melodic-software/ci-workflows#195 — its dogfood self-caller, merged,
  pinned at this same merged SHA.
- melodic-software/ci-workflows#192 — end-to-end proof the self-caller
  actually applies the floor label live.
- melodic-software/claude-code-plugins#850 — the consumer PR blocked on
  this contract (its `Runner policy` check fails without it).
- melodic-software/claude-code-plugins#506 — the issue driving that
caller.

## Test plan
- [x] `npm run test:runner-policy` (227 passing)
- [x] `npm run lint:runner-policy` ("Runner policy passed.")
- [x] `npm run lint:md`
- [x] `npm run lint:hooks`
- [x] `lefthook` pre-commit gate (typos, gitleaks, editorconfig, biome)
@claude

claude Bot commented Jul 21, 2026

Copy link
Copy Markdown
Contributor

Claude finished @kyle-sexton's task in 1m 34s —— View job


PR Review

  • Gather context and read changed file
  • Review workflow for correctness, security, and convention alignment
  • Assess CI blocking situation
  • Post findings

Review: .github/workflows/issue-triage-label.yml

LGTM — no blocking issues found.

Correctness

The file is 23 lines and contains exactly the required structure for a thin caller: trigger, top-level permissions denial, single job with scoped grant, and a pinned uses: reference with one explicit with: input.

  • Triggerissues: [opened, reopened] is the correct pair. reopened ensuring re-application when a tier was cleared while closed is a sound design choice, documented in the header comment.
  • Reusable defaultslabel (priority: needs-triage) and label-prefix (priority:) are not overridden; the PR confirms these already match this repo's label taxonomy and gh label list verified the label exists. No unnecessary with: inputs.
  • Non-gating — correct framing; the header comment explains this clearly.

Security

Dimension Status
Supply-chain pin Full 40-char SHA c5e729c0af0e55ffed4675ec85c1b57356fef79e — immutable, gold standard ✓
Same-org target melodic-software/ci-workflows — no external trust delegation ✓
Permissions permissions: {} at workflow scope; issues: write at job scope only ✓
secrets: inherit Absent — zero secrets forwarded to the reusable ✓
Injection surfaces No run: blocks; only with: runner: ubuntu-24.04 (static literal, no context interpolation) ✓
zizmor --persona=pedantic 0 findings per PR description ✓

Convention alignment (sibling callers)

Checked against pr-issue-linkage.yml, do-not-merge.yml, and link-check.yml:

  • permissions: {} at workflow level, narrowed to issues: write at job level — matches the pattern used by pr-issue-linkage.yml (which also needs write access) ✓
  • runner: ubuntu-24.04 passed explicitly — consistent with all three sibling callers ✓
  • SHA pin comment format (# <short-sha> <date>) — consistent ✓
  • No concurrency block — correct omission; issues: opened/reopened are discrete per-issue events with no stacking concern, unlike the pull_request_target siblings ✓

CI blocking situation — resolved

The previous Runner policy failure (reported at 16:13Z) was caused by the absence of an approvedReusableWorkflowContracts entry for issue-triage-label.yml@c5e729c in .github/standards/runner-policy/policy.json.

That entry is now present on this branch:

"melodic-software/ci-workflows/.github/workflows/issue-triage-label.yml@c5e729c0af0e55ffed4675ec85c1b57356fef79e": {
  "routing": "runner-input",
  "runnerInput": "runner",
  "allowedInputs": ["runner", "label", "label-prefix"],
  "allowedSecrets": {},
  "allowedCallerPermissions": {
    "issues": "write"
  }
}

This arrived via chore: sync standards components (#873) merging to main, followed by the Merge branch 'main' into ci/506-triage-label-caller commit (7ef6ab4). The contract entries are exact-match for what the caller passes — runner-input routing, runner as the input, issues: write as the only caller permission. The blocker is cleared.

Current CI: pr-title, pr-issue-linkage, and do-not-merge have all passed; ci, claude-review, and claude-security-review are in progress with no failures.


No changes requested. The file is correct, minimal, secure, and follows all established conventions. Ready to merge once in-progress CI checks complete.

@claude

claude Bot commented Jul 21, 2026

Copy link
Copy Markdown
Contributor

Claude finished @kyle-sexton's task in 1m 2s —— View job


Security Review

  • Gather context
  • Read changed workflow file
  • Analyze trigger and permission structure
  • Analyze supply-chain / pin risk
  • Analyze injection surfaces
  • Post findings

No security issues found.

The file is a single, minimal reusable-workflow caller with no run: steps. Each risk dimension is addressed:

Trigger (L11–13): issues: opened/reopened is a safe trigger. Unlike pull_request_target or workflow_run, it does not run with elevated permissions over untrusted fork code, does not surface the caller's secrets to forked code, and carries no implicit cross-boundary privilege. No elevated-trigger risk.

Permission structure (L15–19): Top-level permissions: {} is a complete deny at workflow scope. The only grant is issues: write scoped to the job — the minimum required to read and apply labels. contents, pull-requests, actions, and all other permissions remain denied. No secrets: inherit, so zero secrets are forwarded to the called workflow; the worst a compromised reusable could do with these grants is read/write issue labels.

Supply-chain (L21): Pinned to the full 40-character immutable commit SHA c5e729c0af0e55ffed4675ec85c1b57356fef79e. No mutable branch or tag ref. Target is the same-org melodic-software/ci-workflows, limiting external trust delegation.

Injection surfaces: There are no run: steps anywhere in the file, eliminating all script-injection risk. The only with: input is the static literal string ubuntu-24.04 — no ${{ github.event.* }} or other attacker-controllable context variable is interpolated anywhere.

Secrets: No secrets: inherit, no direct secret references.

Concurrency: Absent, which is correct — issues: events are discrete per issue (no stale-run stacking concern), unlike the pull_request_target siblings where concurrency cancellation is necessary.

@kyle-sexton
kyle-sexton merged commit 841dec9 into main Jul 21, 2026
23 checks passed
@kyle-sexton
kyle-sexton deleted the ci/506-triage-label-caller branch July 21, 2026 17:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

automation: auto-apply 'priority: needs-triage' to new issues lacking a priority label

1 participant