Skip to content

Remove expression support from skills frontmatter; add skills to gh-aw-manifest#42676

Open
Copilot wants to merge 4 commits into
mainfrom
copilot/remove-github-actions-support
Open

Remove expression support from skills frontmatter; add skills to gh-aw-manifest#42676
Copilot wants to merge 4 commits into
mainfrom
copilot/remove-github-actions-support

Conversation

Copilot AI commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

Skills refs must be statically resolvable at compile time — ${{ inputs.skill_ref }} and owner/repo@${{ github.sha }} expressions cannot be audited, pinned, or recorded deterministically. This removes expression support entirely and records the resulting static skill list in the manifest.

Validation changes (skills_frontmatter.go)

  • Drop skillSpecExpressionRefRegexp and githubActionsExpressionRegexp
  • validateSkillSpecValue now only accepts owner/repo@<40-hex-char-sha> or owner/repo/skill/path@<40-hex-char-sha>
  • Before: ${{ inputs.skill_ref }} → valid; After: → compile error

Manifest (safe_update_manifest.go, compiler_yaml.go)

  • Add Skills []string (sorted, deduplicated, omitempty) to GHAWManifest
  • NewGHAWManifest gains a skillSpecs []string parameter; compiler passes data.Skills
  • Skills now appear in the # gh-aw-manifest: lock-file header alongside secrets, actions, and containers

Tests

  • skills_frontmatter_test.go: flip "accepts github actions expressions" → "rejects github actions expressions"; remove expression cases from TestIsRepositorySkillSpec
  • activation_skills_step_test.go: remove TestBuildActivationJob_AddsExpressionSkillInstallSteps
  • compiler_orchestrator_frontmatter_test.go: TestParseFrontmatterSection_ExpressionSkillsRef now asserts a compile-time error
  • safe_update_manifest_test.go: add skills sorting/dedup coverage; update all NewGHAWManifest call sites
Copilot AI and others added 3 commits July 1, 2026 06:34
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
…r; add skills to gh-aw-manifest

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Copilot AI changed the title Remove GitHub Actions expression support from skills frontmatter; add skills to gh-aw-manifest Jul 1, 2026
Copilot AI requested a review from pelikhan July 1, 2026 06:48
@pelikhan pelikhan marked this pull request as ready for review July 1, 2026 06:48
Copilot AI review requested due to automatic review settings July 1, 2026 06:48
@github-actions

github-actions Bot commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

⚠️ PR Code Quality Reviewer failed during code quality review.

@github-actions

github-actions Bot commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

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

No ADR enforcement needed: PR #42676 does not have the 'implementation' label and has only 59 new lines of code in business logic directories (threshold: 100).

@github-actions

github-actions Bot commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

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

@github-actions

github-actions Bot commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

Test Quality Sentinel completed test quality analysis.

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 makes workflow skills: references statically resolvable at compile time by removing GitHub Actions expression support in skill specs, and records the resulting (static) skill list in the # gh-aw-manifest: header for deterministic auditing/pinning.

Changes:

  • Tightened skills: frontmatter validation to only allow owner/repo@<40-hex-sha> and owner/repo/skill/path@<40-hex-sha> (no ${{ ... }} expressions).
  • Extended gh-aw-manifest to include a sorted/deduplicated skills list and wired it into YAML header generation.
  • Updated/removed tests that previously asserted expression-based skill refs were accepted or propagated.
Show a summary per file
File Description
pkg/workflow/skills_frontmatter.go Removes expression acceptance and enforces static skill spec format.
pkg/workflow/skills_frontmatter_test.go Updates validation expectations to reject expression-based skill refs.
pkg/workflow/safe_update_manifest.go Adds Skills to GHAWManifest and sorts/deduplicates before serialization.
pkg/workflow/safe_update_manifest_test.go Adds coverage for skills sorting/dedup and updates constructor call sites.
pkg/workflow/compiler_yaml.go Passes workflow skills into NewGHAWManifest for lock-header emission.
pkg/workflow/compiler_orchestrator_frontmatter_test.go Expects compile-time error when skills use expressions.
pkg/workflow/activation_skills_step_test.go Removes expression-skill activation job test (no longer supported).
actions/setup/js/add_reaction_and_edit_comment.cjs Pure formatting change (ternary condensed to one line).
.github/workflows/uk-ai-operational-resilience.lock.yml Regenerated lock header content after compiler changes.
.github/workflows/test-quality-sentinel.lock.yml Regenerated lock header content after compiler changes.
.github/workflows/pr-sous-chef.lock.yml Regenerated lock header content after compiler changes.
.github/workflows/impeccable-skills-reviewer.lock.yml Regenerated lock header content after compiler changes.
.github/workflows/daily-geo-optimizer.lock.yml Regenerated lock header content after compiler changes.

Review details

Tip

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

  • Files reviewed: 13/13 changed files
  • Comments generated: 2
  • Review effort level: Low
Comment thread pkg/workflow/safe_update_manifest.go Outdated
Version int `json:"version"`
Secrets []string `json:"secrets"`
Actions []GHAWManifestAction `json:"actions"`
Skills []string `json:"skills,omitempty"` // frontmatter skill specs (owner/repo@sha), sorted
Comment on lines 124 to +127
// Embed the gh-aw-manifest immediately after gh-aw-metadata for easy machine parsing.
// The manifest records all secrets, external actions, and container images detected at
// compile time so that subsequent compilations can perform safe update enforcement.
manifest := NewGHAWManifest(secrets, actions, data.ActionResolutionFailures, data.DockerImagePins, data.Redirect)
manifest := NewGHAWManifest(secrets, actions, data.ActionResolutionFailures, data.DockerImagePins, data.Redirect, data.Skills)
@pelikhan

pelikhan commented Jul 1, 2026

Copy link
Copy Markdown
Collaborator
@github-actions

github-actions Bot commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

🧪 Test Quality Sentinel Report

Test Quality Score: 83/100 — Excellent

Analyzed 4 test(s): 4 design, 0 implementation, 0 violation(s).

📊 Metrics (4 tests)
Metric Value
Analyzed 4 (Go: 4, JS: 0)
✅ Design 4 (100%)
⚠️ Implementation 0 (0%)
Edge/error coverage 3 (75%)
Duplicate clusters 0
Inflation YES (minor)
🚨 Violations 0
Test File Classification Issues
TestParseFrontmatterSection_ExpressionSkillsRef compiler_orchestrator_frontmatter_test.go:296 design_test / behavioral_contract None
TestValidateFrontmatterSkills/rejects github actions expressions skills_frontmatter_test.go:50 design_test / behavioral_contract None
TestNewGHAWManifest/skills are sorted and deduplicated safe_update_manifest_test.go:140 design_test / behavioral_contract None
TestNewGHAWManifest/nil skills produces nil skills field safe_update_manifest_test.go:153 design_test / behavioral_contract nil/omitempty edge ✓
⚠️ Flagged Tests (1 — minor inflation note)

skills_frontmatter_test.go — test-to-production additions ratio approximately 3:1 (3 added lines vs 1 in skills_frontmatter.go). The absolute counts are trivially small and the change is a correct refactoring of an existing assertion (NoError → Error + Contains). Not a meaningful inflation concern in practice.

Score Breakdown

Component Calculation Points
Design ratio (4/4) 1.0 × 40 40.0
Edge coverage (3/4) 0.75 × 30 22.5
Duplicate penalty (0 clusters) 20 − 0 20.0
Inflation bonus Inflation detected (minor) 0
Total 82.5 → 83

Verdict

Passed. 0% implementation tests (threshold: 30%). No guideline violations.

This PR correctly removes expression support from skills frontmatter and adds skills tracking to the manifest. All changed tests enforce behavioral contracts: two tests flip from accepting to rejecting GitHub Actions expressions (verifying the new stricter validation policy), and two new table rows verify manifest skills sorting/deduplication and nil/omitempty semantics. The deletion of TestBuildActivationJob_AddsExpressionSkillInstallSteps is appropriate cleanup for the removed feature.

References: §28499128388

Warning

Firewall blocked 1 domain

The following domain was blocked by the firewall during workflow execution:

  • awmgmcpg

To allow these domains, add them to the network.allowed list in your workflow frontmatter:

network:
  allowed:
    - defaults
    - "awmgmcpg"

See Network Configuration for more information.

🧪 Test quality analysis by Test Quality Sentinel · 61.9 AIC · ⌖ 10.5 AIC · ⊞ 6.8K ·
Comment /review to run again

@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: 83/100. 0% implementation tests (threshold: 30%). No guideline violations.

@github-actions

github-actions Bot commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

PR Review: Remove expression support from skills frontmatter 🧠

Applied /codebase-design and /tdd. Overall this is a clean, well-motivated change — 4 small issues found worth addressing.

📋 Issues found (4)
# File Issue
1 safe_update_manifest.go:116 Log reports raw skillSpecs count before deduplication — should use sortedSkills
2 safe_update_manifest_test.go:149 Missing edge-case test for empty-string skill spec filtering
3 compiler_orchestrator_frontmatter_test.go:319 Dead "does not match pattern" branch in error assertion weakens test signal
4 compiler_yaml.go:125 Stale inline comment omits skills from the list of manifest fields

@copilot please address the review comments above.

🧠 Reviewed using Matt Pocock's skills by Matt Pocock Skills Reviewer · 96.8 AIC · ⌖ 7.45 AIC · ⊞ 6.6K ·
Comment /matt to run again

@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.

🧠 Reviewed using Matt Pocock's skills by Matt Pocock Skills Reviewer · 96.8 AIC · ⌖ 7.45 AIC · ⊞ 6.6K
Comment /matt to run again

safeUpdateManifestLog.Printf("Manifest built: version=%d, secrets=%d, actions=%d, containers=%d",
currentGHAWManifestVersion, len(secrets), len(actions), len(sortedContainers))
safeUpdateManifestLog.Printf("Manifest built: version=%d, secrets=%d, actions=%d, containers=%d, skills=%d",
currentGHAWManifestVersion, len(secrets), len(actions), len(sortedContainers), len(skillSpecs))

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.

[/codebase-design] The "Manifest built" log records len(skillSpecs) (the raw input count) before deduplication, so if duplicates are present the logged count will be higher than what ends up in the manifest.

💡 Suggested fix

Move the log after the dedup/sort block, using len(sortedSkills) for consistency with how secrets and actions counts are reported:

sort.Strings(sortedSkills)
if len(sortedSkills) == 0 {
    sortedSkills = nil
}
safeUpdateManifestLog.Printf("Manifest built: version=%d, secrets=%d, actions=%d, containers=%d, skills=%d",
    currentGHAWManifestVersion, len(secrets), len(actions), len(sortedContainers), len(sortedSkills))

@copilot please address this.

wantVersion: 1,
wantSecrets: []string{},
wantSkills: []string{
"githubnext/skills/review/security@1f181b37d3fe5862ab590648f25a292e345b5de6",

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.

[/tdd] The sorted-and-deduplicated test case (line 140–151) only exercises the case where the "lexicographically later" value survives. Consider adding a test case that verifies the first element alphabetically wins — i.e. "githubnext/skills@abc" < "githubnext/skills@xyz" is correctly ordered — and a case with an empty-string skill spec to confirm the blank-filtering path is exercised.

💡 Missing edge cases
{
    name: "empty-string skill specs are filtered out",
    skillSpecs: []string{
        "",
        "githubnext/skills@1f181b37d3fe5862ab590648f25a292e345b5de6",
        "",
    },
    wantVersion: 1,
    wantSecrets: []string{},
    wantSkills: []string{
        "githubnext/skills@1f181b37d3fe5862ab590648f25a292e345b5de6",
    },
},

The validation layer should already prevent empty strings from reaching here, but testing the filtering in NewGHAWManifest directly makes the contract explicit and prevents silent data corruption if something bypasses validation.

@copilot please address this.

require.Error(t, err, "expected error: GitHub Actions expressions are not allowed in skills refs")
assert.Nil(t, result)
assert.True(t,
strings.Contains(err.Error(), "40-char-sha") || strings.Contains(err.Error(), "does not match pattern"),

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.

[/tdd] The assertion on line 319 accepts two different error message substrings ("40-char-sha" OR "does not match pattern"). The second branch ("does not match pattern") does not exist in the current error message produced by validateSkillSpecValue, so this disjunction is dead code. Narrow the assertion to the string that is actually produced.

💡 Suggested simplification

Since validateSkillSpecValue always returns:

skills[N] must use owner/repo@<40-char-sha> or owner/repo/skill/path@<40-char-sha> (got %q). ...

The test can simply assert:

require.ErrorContains(t, err, "40-char-sha")

The "does not match pattern" branch was likely defensive scaffolding from a previous iteration. Keeping it dilutes signal — if the error message ever changes, this test would silently still pass via the wrong branch.

@copilot please address this.

Comment thread pkg/workflow/compiler_yaml.go Outdated
@@ -124,7 +124,7 @@ func (c *Compiler) generateWorkflowHeader(yaml *strings.Builder, data *WorkflowD
// Embed the gh-aw-manifest immediately after gh-aw-metadata for easy machine parsing.
// The manifest records all secrets, external actions, and container images detected at

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.

[/codebase-design] The inline comment on line 124–126 still says "secrets, external actions, and container images" — it does not mention skills. Since skills are now a first-class manifest field alongside secrets and actions, the comment should be updated to stay accurate.

💡 Suggested update
// Embed the gh-aw-manifest immediately after gh-aw-metadata for easy machine parsing.
// The manifest records all secrets, external actions, container images, and skill specs
// detected at compile time so that subsequent compilations can perform safe update enforcement.

@copilot please address this.

Comment thread pkg/workflow/safe_update_manifest.go Outdated
Version int `json:"version"`
Secrets []string `json:"secrets"`
Actions []GHAWManifestAction `json:"actions"`
Skills []string `json:"skills,omitempty"` // frontmatter skill specs (owner/repo@sha), sorted

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.

[/codebase-design] The Skills field is placed between Actions and ResolutionFailures in the struct but the JSON field ordering in the lock file header will follow struct field order. Other manifest fields (Secrets, Actions) are always present (not omitempty), while Skills uses omitempty. This is fine, but consider whether downstream consumers that parse the manifest JSON should be documented as needing to handle a missing skills key — especially tools that detect newly introduced skills as a "safe update" concern.

💡 Context

If safe-update enforcement will eventually compare current manifest skills against a previously compiled manifest to detect newly introduced skills (as it already does for secrets), the omission of the field for zero-skill workflows is correct but worth noting in the struct godoc. Something like:

// Skills records the sorted, deduplicated skill specs from workflow frontmatter.
// Absent (nil) when the workflow has no skills declaration.
Skills []string `json:"skills,omitempty"`

This makes the nil-vs-empty distinction explicit for future maintainers.

@copilot please address this.

@github-actions

github-actions Bot commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

Impeccable Skills Review: Remove expression support from skills frontmatter; add skills to gh-aw-manifest

This is a clean, well-scoped change. Removing expression support from skill specs is the right call — dynamic expressions are not statically auditable and could allow bypasses of the pinning and supply-chain verification the manifest exists to enable.

What works well:

  • validateSkillSpecValue enforces a strict owner/repo@<40-hex-sha> pattern with no expression escape hatch
  • NewGHAWManifest signature extended cleanly; all call sites updated
  • Dedup+sort logic mirrors existing container/secret patterns — consistent and correct
  • omitempty + nil guard prevents empty arrays from appearing in the JSON header
  • Tests updated symmetrically: the expression-acceptance test now asserts a compile error; sorting/dedup coverage added

One nit (see inline comment):
The "Manifest built" log at safe_update_manifest.go:116 uses len(skillSpecs) (raw input) before deduplication completes. After dedup, sortedSkills may be smaller. This could mislead debugging. Suggest logging len(sortedSkills) or moving the log after the dedup block.

Verified clean:

  • Removed regexps (skillSpecExpressionRefRegexp, githubActionsExpressionRegexp) are gone from all production code
  • No remaining expression-passthrough paths for skill specs in the compiler or activation-job builder
  • Lock file diffs are expected recompilation artifacts

Overall: LGTM pending the log nit above.

🧵 Reviewed using Impeccable skills by Impeccable Skills Reviewer · 100.4 AIC · ⌖ 6.72 AIC · ⊞ 4.9K ·

@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.

🧵 Reviewed using Impeccable skills by Impeccable Skills Reviewer · 100.4 AIC · ⌖ 6.72 AIC · ⊞ 4.9K

safeUpdateManifestLog.Printf("Manifest built: version=%d, secrets=%d, actions=%d, containers=%d",
currentGHAWManifestVersion, len(secrets), len(actions), len(sortedContainers))
safeUpdateManifestLog.Printf("Manifest built: version=%d, secrets=%d, actions=%d, containers=%d, skills=%d",
currentGHAWManifestVersion, len(secrets), len(actions), len(sortedContainers), len(skillSpecs))

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.

The "Manifest built" log fires before the dedup loop runs, so len(skillSpecs) here is the raw input count, not the final deduplicated count. If a caller passes duplicate skill specs the log will report a higher number than what actually ends up in the manifest, which could mislead debugging sessions.

Consider moving this log to after sortedSkills is computed (or renaming the placeholder to raw_skills):

safeUpdateManifestLog.Printf("Manifest built: version=%d, secrets=%d, actions=%d, containers=%d, skills=%d",
    currentGHAWManifestVersion, len(secrets), len(actions), len(sortedContainers), len(sortedSkills))

@copilot please address this.

…r; fix manifest comments

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

Copilot AI commented Jul 1, 2026

Copy link
Copy Markdown
Contributor Author

@copilot fix impeccable workflow

https://github.com/github/gh-aw/actions/runs/28499128376/job/84472065029#step:11:1

The impeccable-skills-reviewer.md workflow was using ${{ vars.IMPECCABLE_SKILLS_REF }} (which resolved to needex/skills — a 404 at runtime) as its skill spec. Since my PR requires statically resolvable SHA-pinned refs, that expression no longer compiles.

Fixed in the latest commit by removing the skills: frontmatter from the workflow. The agent instructions already have a graceful fallback: "If no external skills are installed, perform a normal high-signal review focused on correctness and security."

Also tightened the Skills struct field comment and updated the manifest-generation comment in compiler_yaml.go to mention frontmatter skills alongside secrets/actions/containers.

@github-actions

github-actions Bot commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

🤖 PR Triage

Field Value
Category refactor
Risk 🔴 high
Priority high
Score 70 / 100
Action ��� fast_track — expedited human review recommended

Score breakdown: impact 38 + urgency 18 + quality 14

Security/audit-relevant change: removes dynamic expression support from skills frontmatter, improving determinism and auditability. Touches core compilation logic and multiple lock files. Active review in progress (9 comments). Ready for human sign-off.

Generated by 🔧 PR Triage Agent · 38 AIC · ⌖ 10.1 AIC · ⊞ 1.6K ·

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