Skip to content

fix: use union of caller + worker permissions for call-workflow jobs#41387

Open
Copilot wants to merge 6 commits into
mainfrom
copilot/aw-failures-fix-workflow-call-permission
Open

fix: use union of caller + worker permissions for call-workflow jobs#41387
Copilot wants to merge 6 commits into
mainfrom
copilot/aw-failures-fix-workflow-call-permission

Conversation

Copilot AI commented Jun 25, 2026

Copy link
Copy Markdown
Contributor

Smoke Call Workflow has been 100% startup_failure since 2026-06-23. GitHub rejects a workflow_call invocation at startup when any worker job requests a permission level greater than what the calling job grants — the compiler was only setting the caller's declared permissions (contents: read, pull-requests: read) on the call-smoke-workflow-call job, while the worker required issues: write and pull-requests: write.

Changes

Compiler (pkg/workflow/compiler_safe_output_jobs.go)

  • Before: call-workflow job permissions = caller's declared permissions only; emit a warning if insufficient for the worker.
  • After: call-workflow job permissions = union(caller declared, worker job-level). Worker permissions are extracted, cloned from the caller base, and merged in — so the grant automatically covers whatever the worker needs without manual caller annotation.
# call-smoke-workflow-call before
permissions:
  contents: read
  pull-requests: read          # insufficient — worker needs write

# call-smoke-workflow-call after (regenerated lock)
permissions:
  actions: read
  contents: read
  issues: write                # elevated from worker
  pull-requests: write         # elevated from worker

Tests (pkg/workflow/call_workflow_permissions_test.go)

  • Updated existing end-to-end tests to assert union behaviour instead of "caller permissions only".
  • Added TestBuildCallWorkflowJobs_WorkerPermissionsElevateCallerPermissions — directly covers the scenario where the caller declares less than the worker needs.

Comments (pkg/workflow/call_workflow_permissions.go)

  • Updated extractCallWorkflowPermissions doc to reflect it now feeds the merge, not just validation.
  • Removed the stale "never written into the caller's lockfile" note from findUncoveredWorkerPermissions.

Run: https://github.com/github/gh-aw/actions/runs/28156255243

Generated by 👨‍🍳 PR Sous Chef · 73.8 AIC · ⌖ 0.98 AIC · ⊞ 17.1K ·

Copilot AI and others added 2 commits June 25, 2026 06:09
The call-workflow job's permission envelope is now computed as the union
of the caller's declared permissions and the worker's job-level permissions.

Previously the compiler only set the caller's declared permissions on the
call-workflow job and warned when they were insufficient for the worker.
GitHub rejects a workflow_call invocation at startup when any worker job
requests a permission level greater than the caller job grants, causing
100% startup_failure on the Smoke Call Workflow since 2026-06-23.

The fix: after extracting worker permissions, clone the caller's
permissions and merge the worker's permissions in. The resulting union
becomes the call-workflow job's effective permission envelope, ensuring
it always covers what the worker needs.

Smoke Call Workflow lock regenerated: call-smoke-workflow-call now
grants actions: read, contents: read, issues: write, pull-requests: write
(union of caller's contents: read, pull-requests: read and the worker's
issues: write, pull-requests: write, actions: read).

Closes #41355

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
…owJobs

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Copilot AI changed the title [WIP] Fix workflow_call permission grant in smoke call workflow fix: use union of caller + worker permissions for call-workflow jobs Jun 25, 2026
Copilot AI requested a review from pelikhan June 25, 2026 06:18
@pelikhan pelikhan marked this pull request as ready for review June 25, 2026 06:25
Copilot AI review requested due to automatic review settings June 25, 2026 06:25
@github-actions

github-actions Bot commented Jun 25, 2026

Copy link
Copy Markdown
Contributor

🧠 Matt Pocock Skills Reviewer has completed the skills-based review. ✅

@github-actions

github-actions Bot commented Jun 25, 2026

Copy link
Copy Markdown
Contributor

Design Decision Gate 🏗️ completed the design decision gate check.

@github-actions

github-actions Bot commented Jun 25, 2026

Copy link
Copy Markdown
Contributor

Test Quality Sentinel completed test quality analysis.

TQS analysis for PR #41387 already completed in this workflow run (28151256398): comment posted (score 80/100 PASS) and APPROVE review submitted. Both add_comment and submit_pull_request_review limits were consumed. No further action needed.

@github-actions

github-actions Bot commented Jun 25, 2026

Copy link
Copy Markdown
Contributor

PR Code Quality Reviewer completed the code quality review.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown
Contributor

🏗️ Design Decision Gate — ADR Required

This PR makes significant changes to core business logic (148 new lines in pkg/workflow/) but does not have a linked Architecture Decision Record (ADR).

📄 Draft ADR committed: docs/adr/41387-union-caller-worker-permissions-for-call-workflow-jobs.md — review and complete it before merging.

🔒 This PR cannot merge until an ADR is linked in the PR body.

📋 What to do next
  1. Review the draft ADR committed to your branch — it was generated from the PR diff
  2. Complete the missing sections — add context the AI could not infer, refine the decision rationale, and list real alternatives you considered
  3. Commit the finalized ADR to docs/adr/ on your branch
  4. Reference the ADR in this PR body by adding a line such as:

    ADR: ADR-41387: Union Caller and Worker Permissions for Call-Workflow Jobs

Once an ADR is linked in the PR body, this gate will re-run and verify the implementation matches the decision.

❓ Why ADRs Matter

"AI made me procrastinate on key design decisions. Because refactoring was cheap, I could always say 'I'll deal with this later.' Deferring decisions corroded my ability to think clearly."

ADRs create a searchable, permanent record of why the codebase looks the way it does. Future contributors (and your future self) will thank you.

📋 Michael Nygard ADR Format Reference

An ADR must contain these four sections to be considered complete:

  • Context — What is the problem? What forces are at play?
  • Decision — What did you decide? Why?
  • Alternatives Considered — What else could have been done?
  • Consequences — What are the trade-offs (positive and negative)?

All ADRs are stored in docs/adr/ as Markdown files numbered by PR number (e.g., 41387-union-caller-worker-permissions-for-call-workflow-jobs.md for PR #41387).

🏗️ ADR gate enforced by Design Decision Gate 🏗️ · 39 AIC · ⌖ 9.56 AIC · ⊞ 8.4K ·

@github-actions

Copy link
Copy Markdown
Contributor

Test Quality Score: 80/100 ✅ Excellent

PR: fix: use union of caller + worker permissions for call-workflow jobs
File analyzed: pkg/workflow/call_workflow_permissions_test.go (unit, //go:build !integration)

1 new test function added, 5 existing tests updated to match the new behavioral contract. All 6 tests verify observable compiler output (job-level permissions in the compiled lockfile), making them high-value behavioral contract tests. The test inflation ratio is notable (27.5×) but contextually appropriate — a focused 4-line logic fix required broad test-suite alignment.

📊 Metrics & Classification
Component Score Notes
Behavioral Coverage 40/40 6/6 tests classified as design tests
Error/Edge Case Coverage 30/30 All 6 include error-path or edge-case assertions
Low Duplication 20/20 No duplicate clusters
Proportional Growth 0/10 Test inflation: +110 test lines vs +4 production lines (27.5:1)

Test-function classification table

Test Function Type Value Edge Cases
TestBuildCallWorkflowJobs_SetsPermissionsFromLockYML Design High require.True job exists; caller already covers worker
TestBuildCallWorkflowJobs_SetsPermissionsFromMD Design High require.True job exists; same-batch MD worker
TestBuildCallWorkflowJobs_WorkerPermissionsElevateCallerPermissions (new) Design High require.NoError on build; under-privileged caller elevated by worker
TestCallWorkflowJobYAMLOutput_WithPermissions Design High YAML output format verified; caller already covers worker
TestCallWorkflowPermissions_EndToEnd Design High Multi-worker end-to-end; assertions flipped from NotContains to Contains
TestCallWorkflowPermissions_EndToEnd_YMLWorker Design High .yml (not .lock.yml) worker path; elevation verified
🔍 Guidelines Compliance

Build tags: ✅ //go:build !integration on line 1; no new test files added.

Mock libraries: ✅ None. No gomock, testify/mock, .EXPECT(), or .On() usage.

Assertion messages: ✅ All testify assertions carry descriptive message arguments.

⚠️ Test Inflation Note

The test file grew at 27.5× the rate of the production file (+110 vs +4 lines). This triggers the inflation penalty (−10 pts) but is contextually justified: the production fix changed the permission-union logic and 5 existing tests had assertions that were explicitly wrong under the new contract (NotContainsContains). The new TestBuildCallWorkflowJobs_WorkerPermissionsElevateCallerPermissions fills a previously absent coverage gap (under-privileged caller scenario).


Verdict: PASS — 0% implementation tests (threshold: 30%), no coding-guideline violations.

References:

🧪 Test quality analysis by Test Quality Sentinel · 79.2 AIC · ⌖ 11.7 AIC · ⊞ 8.4K ·

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Test Quality Sentinel: 80/100. Test quality is acceptable — 0% of new tests are implementation tests (threshold: 30%). No coding-guideline violations detected.

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Skills-Based Review 🧠

Applied /diagnose and /tdd — approving. The fix correctly addresses the root cause and ships a well-targeted regression test. Three non-blocking suggestions below.

📋 Key Themes & Highlights

Key Themes

  • findUncoveredWorkerPermissions is now dead in production — the function exists in call_workflow_permissions.go and has test coverage, but is no longer called from any non-test code path. Worth resolving (repurpose for a diagnostic info message, or remove).
  • Silent elevation — the old code warned users via stderr when caller permissions were insufficient; the new code auto-promotes silently. A brief compile-time info message would preserve transparency without blocking the build.
  • callerPerms == nil + worker-has-perms — the merged = NewPermissions() fallback branch is untested directly.

Positive Highlights

  • TestBuildCallWorkflowJobs_WorkerPermissionsElevateCallerPermissions directly names and pins the invariant that was broken — exactly the right regression test structure.
  • callerPerms.Clone() before Merge is the correct defensive pattern — original data.CachedPermissions is never mutated.
  • ✅ PR description is detailed and includes before/after YAML, making it easy to reason about the change.
  • ✅ Lock file regeneration confirms the fix is end-to-end correct for the Smoke Call Workflow.
  • ✅ Test comment updates accurately reflect the new union semantics throughout.

🧠 Reviewed using Matt Pocock's skills by Matt Pocock Skills Reviewer · 90.2 AIC · ⌖ 8.85 AIC · ⊞ 6.5K

Comments that could not be inline-anchored

pkg/workflow/compiler_safe_output_jobs.go:329

[/diagnose] Silent elevation — users lose compiler feedback when permissions are auto-promoted.

The old code emitted a visible warning to stderr when the caller's declared permissions were insufficient. The new code silently elevates and only logs internally. A caller who deliberately set a minimal permissions: block (for least-privilege reasons) will have no compile-time signal that the block was expanded.

<details>
<summary>💡 Suggestion: emit an info-level compiler message on eleva…

pkg/workflow/call_workflow_permissions.go:33

[/diagnose] findUncoveredWorkerPermissions is no longer called from any production code path — only from test assertions.

With the new union-based approach, Merge subsumes this function's role. The function still documents the ranking semantics clearly, but its continued existence without a production caller can be confusing. Consider one of:

<details>
<summary>💡 Options</summary>

  1. Repurpose it for a compile-time info message (see comment on compiler_safe_output_jobs.go) — t…
pkg/workflow/call_workflow_permissions_test.go:454

[/tdd] Missing edge case: caller has no permissions: block but the worker declares permissions.

The existing test checks caller=nil + worker=no-perms (empty merge → no permissions on job). But the merged = NewPermissions() branch (line 326 of compiler_safe_output_jobs.go) handles caller=nil + worker=has-perms — and this path isn't directly exercised.

<details>
<summary>💡 Suggested test skeleton</summary>

func TestBuildCallWorkflowJobs_NilCallerPerms_WorkerPermsApplied(t *tes</details>

<details><summary>pkg/workflow/compiler_safe_output_jobs.go:307</summary>

**[/zoom-out]** `effectivePerms` is aliased to `callerPerms` as the initial value, then conditionally replaced by `merged`. This works correctly, but the intent is slightly obscureda reader needs to trace both branches to understand when `effectivePerms != callerPerms`.

&lt;details&gt;
&lt;summary&gt;💡 Optional readability improvement&lt;/summary&gt;

The current pattern:
```go
effectivePerms := callerPerms
if markdownPath != &quot;&quot; {
    ...
    effectivePerms = merged
}

An alternative that makes the defa…

pkg/workflow/call_workflow_permissions_test.go:392

[/tdd] TestBuildCallWorkflowJobs_WorkerPermissionsElevateCallerPermissions is exactly the right regression test — it names the invariant in the function signature, documents the real-world scenario in comments, and asserts the specific permission scopes that the bug was silently violating. Well structured with clear Arrange / Act / Assert flow.

One small sharpening opportunity: asserting NotContains(t, job.Permissions, &quot;pull-requests: read&quot;) alongside the existing `Contains(..., "pul…

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR updates the gh-aw compiler’s handling of reusable workflow_call invocations emitted by the call-workflow safe output. The goal is to prevent GitHub Actions startup_failure when a called (worker) workflow’s jobs require higher GITHUB_TOKEN permissions than the caller job grants, by computing call-job permissions as a merged envelope.

Changes:

  • Update buildCallWorkflowJobs to compute call-job permissions from the caller + extracted worker permissions, and emit the merged permissions onto the call-* job.
  • Update permission-extraction docs and expand tests to assert the new union behavior (including elevation when worker needs more than the caller declares).
  • Regenerate smoke-call-workflow.lock.yml so the call job grants the worker-required permissions.
Show a summary per file
File Description
pkg/workflow/compiler_safe_output_jobs.go Merges caller + worker permission requirements to set call-job permissions for workflow_call jobs.
pkg/workflow/call_workflow_permissions.go Updates doc comments to reflect permission extraction feeding merge behavior.
pkg/workflow/call_workflow_permissions_test.go Updates and adds tests for union/elevation behavior for call-workflow job permissions.
.github/workflows/smoke-call-workflow.lock.yml Regenerated lockfile reflecting elevated call-job permissions needed by the worker.

Copilot's findings

Tip

Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

  • Files reviewed: 5/5 changed files
  • Comments generated: 4

Comment on lines +307 to 311
effectivePerms := callerPerms
if markdownPath != "" {
workerPerms, permErr := extractCallWorkflowPermissions(workflowName, markdownPath)
if permErr != nil {
// Non-fatal: log and continue. The worker file may not exist yet (it may be
// the caller job always grants at least what the worker requires, preventing GitHub from
// rejecting the run at startup when the worker requests a level higher than the caller granted.
//
// Returns nil when no workflow file is found or no permissions are declared.
Comment thread pkg/workflow/call_workflow_permissions_test.go Outdated
Comment on lines +322 to +329
var merged *Permissions
if callerPerms != nil {
merged = callerPerms.Clone()
} else {
merged = NewPermissions()
}
merged.Merge(workerPerms)
effectivePerms = merged

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

REQUEST_CHANGES — three issues must be addressed before merge: silent escalation destroys the audit trail, the error fallback silently reintroduces the exact startup_failure class this PR targets, and findUncoveredWorkerPermissions is now dead production code.

Blocking themes

Silent permission escalation removes the audit trail

The c.IncrementWarningCount() call and stderr warning were the only user-visible signal that a compiled lockfile grants more scope than the caller's markdown declares. Removing them means a worker update can silently widen every caller job's GITHUB_TOKEN with no indication to the author or security reviewer. The fix should keep the auto-elevation but restore an info-level message so the grant is auditable.

Error fallback bypasses the fix silently

When extractCallWorkflowPermissions fails (malformed worker YAML, path error), the call job falls back to caller-only permissions — the exact insufficient-permissions condition that caused startup_failure. This failure is logged internally but invisible to the user. A compiler warning (c.IncrementWarningCount()) is needed here so authors know auto-elevation was skipped.

findUncoveredWorkerPermissions is now dead production code

Removing the production call-site without removing the function leaves a function whose unit tests give false confidence that permission-coverage analysis is active during compilation. Either delete it (and its tests) or wire it back in as part of the audit-trail fix above.

🔎 Code quality review by PR Code Quality Reviewer · 103.2 AIC · ⌖ 10.5 AIC · ⊞ 5.2K

// This is used to validate (not modify) the caller's permission envelope: callers
// control their own permission surface, and the compiler only warns when the declared
// permissions are insufficient for a worker the caller invokes.
func findUncoveredWorkerPermissions(caller, worker *Permissions) []string {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

findUncoveredWorkerPermissions is dead production code — its only production call-site was removed in this PR, leaving a function exercised solely by its own unit tests.

💡 Details

The production call in compiler_safe_output_jobs.go was removed by this PR. The function now appears only in call_workflow_permissions_test.go, where tests validate the function's own internal logic — not any active compilation behavior.

Consequences:

  • Future maintainers have no signal that this function is inert; there is no production call-site reference anywhere.
  • Unit tests for this function create false confidence that permission-coverage analysis runs during compilation.
  • This function can be deleted tomorrow and no production behavior changes.

Fix: Either remove the function and its tests, or explicitly document it as a utility kept for future use.

}
}

if effectivePerms != nil {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Silent permission escalation removes the only user-visible audit signal — a worker update can now silently widen every caller job's GitHub token with no warning, no counter increment, and no feedback to the workflow author.

💡 Details

The old code emitted a stderr warning and called c.IncrementWarningCount() when the caller's declared permissions were insufficient. That was the mechanism by which authors could discover that their compiled lockfile was granting more scope than their source declared.

The new code silently elevates. An author who writes:

permissions:
  contents: read
  pull-requests: read

gets a lockfile with issues: write, pull-requests: write, and actions: read — and receives zero indication this happened.

Why this matters:

  1. Worker-driven escalation: Any worker update that adds a new permission scope silently widens every caller job's GITHUB_TOKEN without the caller author's knowledge or review.
  2. Auditability: Security reviewers examining the markdown source see one permission envelope; the compiled artifact has a different, broader one.
  3. POLA: The caller's declared scope is no longer the effective scope.

Suggested fix: Keep the auto-elevation (it fixes the startup_failure) but restore the audit signal as an info-level message:

merged.Merge(workerPerms)
effectivePerms = merged
if elevated := findUncoveredWorkerPermissions(callerPerms, workerPerms); len(elevated) > 0 {
    fmt.Fprintln(os.Stderr, formatCompilerMessage(markdownPath, "info",
        fmt.Sprintf("call-workflow target '%s' requires additional permissions (%s); auto-added to call-workflow job.",
            workflowName, strings.Join(elevated, ", "))))
}

This preserves the findUncoveredWorkerPermissions function (which would otherwise be dead code) and gives authors an audit trail.

compilerSafeOutputJobsLog.Printf("Could not extract worker permissions for call-workflow job '%s' (validation skipped): %v", jobName, permErr)
// compiled in the same batch), in which case we fall back to the caller's
// own declared permissions.
compilerSafeOutputJobsLog.Printf("Could not extract worker permissions for call-workflow job '%s' (falling back to caller-only permissions): %v", jobName, permErr)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Error fallback silently reintroduces the startup_failure class — when worker permission extraction fails, the call job gets caller-only permissions and the PR's fix is bypassed with no user-visible signal.

💡 Details

When extractCallWorkflowPermissions returns a non-nil error, effectivePerms stays as callerPerms (the fallback on line 307). This is exactly the caller-insufficient-permissions scenario that caused the startup_failure this PR claims to fix. The failure is only emitted as a debug-level internal log — not surfaced to the user.

This can happen when:

  • A worker .lock.yml file is present but contains malformed YAML
  • A path resolution error occurs inside findWorkflowFile
  • File permissions prevent reading the worker file

In all these cases, the caller job compiles silently with insufficient permissions, and the run fails at startup — the same class of failure the PR description says is now fixed.

Suggested fix: Surface the extraction failure as a compiler warning so the author knows the auto-elevation was skipped:

if permErr != nil {
    fmt.Fprintln(os.Stderr, formatCompilerMessage(markdownPath, "warning",
        fmt.Sprintf("Could not extract worker permissions for '%s' (falling back to caller-only; startup_failure possible): %v",
            workflowName, permErr)))
    c.IncrementWarningCount()
}

// Validate (without modifying) that the caller's declared permissions cover what
// the worker requires. Emit a warning when they do not, so the user can widen the
// caller's `permissions:` block. This never alters the compiled permissions.
effectivePerms := callerPerms

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

effectivePerms aliases data.CachedPermissions without cloning in the non-merge path — any future mutation through this reference will silently corrupt the shared cache across loop iterations.

💡 Details
effectivePerms := callerPerms  // direct alias; callerPerms may point to data.CachedPermissions

When workerPerms == nil or markdownPath == "", effectivePerms is never replaced with the cloned merged value, so it retains the alias. Today RenderToYAML() is read-only and there is no bug. But the pattern is a trap: any future effectivePerms.Set(...) or effectivePerms.Merge(...) call on the fallback path would silently mutate data.CachedPermissions, corrupting permissions for every subsequent workflow in the outer loop.

Note the merge path correctly clones: merged = callerPerms.Clone(). The fallback path should match that discipline:

var effectivePerms *Permissions
if callerPerms != nil {
    effectivePerms = callerPerms.Clone()
}

This makes ownership explicit and eliminates the shared-state aliasing risk entirely.

// automatically promotes the call-workflow job's permissions to the union of both.
// This prevents GitHub's startup_failure when a reusable workflow job requests a
// permission level greater than the caller grants.
func TestBuildCallWorkflowJobs_WorkerPermissionsElevateCallerPermissions(t *testing.T) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

New test only covers the happy path — there is no test asserting that a permissions extraction error falls back to caller-only permissions without crashing or silently emitting empty permissions.

💡 Details

buildCallWorkflowJobs has a specific error-recovery branch: when extractCallWorkflowPermissions returns a non-nil error, it logs and continues with effectivePerms = callerPerms. This is new behavior (the fallback path changed semantics in this PR), but it has no test coverage.

A regression here could silently produce a call job with empty permissions (e.g., if effectivePerms were nil after the error) or panic on a nil dereference if callerPerms itself is nil after a parse failure.

Suggested addition: A test that writes a malformed .lock.yml for the worker and asserts:

  1. buildCallWorkflowJobs returns no error.
  2. The generated call job carries the caller's declared permissions (not empty).
func TestBuildCallWorkflowJobs_WorkerExtractionError_FallsBackToCallerPerms(t *testing.T) {
    // Write a malformed worker file so extraction fails
    require.NoError(t, os.WriteFile(
        filepath.Join(workflowsDir, "worker-bad.lock.yml"),
        []byte("not: valid: yaml: [::"), 0644))
    // ... build jobs, assert caller permissions are set, no panic
}

@pelikhan

Copy link
Copy Markdown
Collaborator

@copilot run pr-finisher skill

…style

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>

Copilot AI commented Jun 25, 2026

Copy link
Copy Markdown
Contributor Author

@copilot run pr-finisher skill

Ran the pr-finisher skill and addressed all four review threads from the automated reviewer in commit 852c819:

  1. Shorthand permissions bug (compiler_safe_output_jobs.go:322-329) — replaced callerPerms.Clone() + Merge(workerPerms) with NewPermissions()Merge(callerPerms)Merge(workerPerms), so shorthand values like read-all are correctly expanded before worker scopes are layered on top.

  2. Doc comment accuracy (call_workflow_permissions.go:111) — updated the doc to reflect that compiled YAML workers always return a non-nil (possibly empty) *Permissions, while nil is only returned when no file is found or the .md frontmatter has no permissions.

  3. Style consistency (call_workflow_permissions_test.go:429 and 3 other occurrences) — replaced new("1") with strPtr("1") across all 4 call sites to match the existing test helper.

  4. Workflow-level permissions limitation (call_workflow_permissions.go:62) — added documentation to extractJobPermissionsFromParsedWorkflow noting that jobs without a per-job permissions block are skipped, and recommending workers declare explicit per-job permissions for reliable extraction.

Local validation (make fmt, make lint, make test-unit, make recompile) all pass.

@github-actions

Copy link
Copy Markdown
Contributor

@copilot please summarize the remaining blockers and post the next concrete step.

Generated by 👨‍🍳 PR Sous Chef · 38 AIC · ⌖ 0.982 AIC · ⊞ 17.1K ·

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.

3 participants