Skip to content

Support authenticated Agent Plugin installation from private repositories - #56505

Merged
pelikhan merged 9 commits into
mainfrom
copilot/support-authenticated-agent-plugin-installation
Aug 28, 2026
Merged

Support authenticated Agent Plugin installation from private repositories#56505
pelikhan merged 9 commits into
mainfrom
copilot/support-authenticated-agent-plugin-installation

Conversation

Copilot AI commented Aug 28, 2026

Copy link
Copy Markdown
Contributor

Private Agent Plugin marketplaces are common in enterprises, but plugins: had no way to authenticate against private repositories — the checkout step always used the workflow's default github.token. This adds opt-in per-plugin credentials, mirroring the existing skills: feature.

Frontmatter

  • Added object-form plugins: entries alongside the existing string form: plugin, github-token, github-app (mutually exclusive).
  • Public plugins and existing string/array syntax are unaffected — no configuration required.
plugins:
  - octo-org/agent-plugin@v1  # unchanged, public

  - plugin: octo-org/private-plugin@main
    github-token: ${{ secrets.PRIVATE_PLUGIN_TOKEN }}

  - plugin: octo-org/private-marketplace/plugins/example@main
    github-app:
      client-id: ${{ vars.PLUGIN_APP_CLIENT_ID }}
      private-key: ${{ secrets.PLUGIN_APP_PRIVATE_KEY }}

Compilation

  • New PluginReference type carries per-entry auth through validation, merging/deduping, and SHA-pinning, mirroring SkillReference.
  • github-app credentials are minted into a short-lived installation token by the compiler before engine-specific plugin install steps run, then injected as token: on that plugin's actions/checkout step. This is engine-agnostic: checkout always happens ahead of any engine-specific install command, so no per-engine changes were needed (this also addresses the concern raised in review that plugin support is implemented separately by each engine).
  • Without github-token/github-app, behavior is unchanged: no token: override, checkout falls back to the default github.token.
  • JSON schema updated to accept the new object form for plugins: entries.

Docs

  • reference/frontmatter.md updated to document object-form plugins: entries and drop the now-inaccurate "plugins can't be private" note.

Copilot AI and others added 3 commits August 28, 2026 04:27
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
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 [WIP] Add support for authenticated Agent Plugin installation from private repositories Support authenticated Agent Plugin installation from private repositories Aug 28, 2026
Copilot AI requested a review from pelikhan August 28, 2026 04:48
@pelikhan

Copy link
Copy Markdown
Collaborator

@copilot add workflow test integration test for each agentic engine that supports plugins

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

Copilot AI commented Aug 28, 2026

Copy link
Copy Markdown
Contributor Author

@copilot add workflow test integration test for each agentic engine that supports plugins

Added TestPrivatePluginAuthAcrossEngines in pkg/workflow/plugins_engine_auth_integration_test.go (commit 1bda5ff-ish, latest push): full-compile integration tests verifying github-token/github-app injection into the plugin checkout step for Copilot, Claude, Codex, and a custom behavior-defined engine (mirroring cursor/kiro).

@pelikhan

Copy link
Copy Markdown
Collaborator

@copilot ensure the generate code issues the correct token for each plugin, add tests

@pelikhan
pelikhan marked this pull request as ready for review August 28, 2026 10:57
Copilot AI balanced review requested due to automatic review settings August 28, 2026 10:57
@github-actions

github-actions Bot commented Aug 28, 2026

Copy link
Copy Markdown
Contributor

Design Decision Gate 🏗️ failed to deliver outputs during design decision gate check.

Warning

Firewall blocked 1 domain

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

  • proxy.golang.org

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

network:
  allowed:
    - defaults
    - "proxy.golang.org"

See Network Configuration for more information.

🏗️ ADR gate enforced by Design Decision Gate 🏗️

@github-actions

github-actions Bot commented Aug 28, 2026

Copy link
Copy Markdown
Contributor

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

🧠 Reviewed using Matt Pocock's skills by Matt Pocock Skills Reviewer

@github-actions

github-actions Bot commented Aug 28, 2026

Copy link
Copy Markdown
Contributor

PR Code Quality Reviewer completed the code quality review.

🔎 Code quality review by PR Code Quality Reviewer

@github-actions

github-actions Bot commented Aug 28, 2026

Copy link
Copy Markdown
Contributor

⚠️ Security scanning failed for Ponytail Reviewer. Review the logs for details.

Warning

Firewall blocked 4 domains

The following domains were blocked by the firewall during workflow execution:

  • ab.chatgpt.com
  • api.github.com
  • chatgpt.com
  • github.com

[!TIP]
api.github.com is blocked because GitHub API access uses the built-in GitHub tools by default. Instead of adding api.github.com to network.allowed, use tools.github.mode: gh-proxy for direct pre-authenticated GitHub CLI access without requiring network access to api.github.com:

tools:
  github:
    mode: gh-proxy

See GitHub Tools for more information on gh-proxy mode.

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

network:
  allowed:
    - defaults
    - "ab.chatgpt.com"
    - "api.github.com"
    - "chatgpt.com"
    - "github.com"

See Network Configuration for more information.

Generated by Ponytail Reviewer for #56505

@github-actions

github-actions Bot commented Aug 28, 2026

Copy link
Copy Markdown
Contributor

Test Quality Sentinel completed test quality analysis.

Test Quality Sentinel skipped because pre-fetch PR data was unavailable: unable to fetch test file diff

Warning

Firewall blocked 1 domain

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

  • github.com

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

network:
  allowed:
    - defaults
    - "github.com"

See Network Configuration for more information.

🧪 Test quality analysis by Test Quality Sentinel

… tests

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

Copilot AI commented Aug 28, 2026

Copy link
Copy Markdown
Contributor Author

@copilot ensure the generate code issues the correct token for each plugin, add tests

Found and fixed a real issue (cb15d74): when the same plugin path is declared twice (e.g. main workflow + import) and the higher-version declaration wins during merge, its credential previously replaced the whole entry — silently dropping a github-token/github-app set on the other declaration, so the checkout step fell back to the default token instead of the configured one. Now the credential is preserved across the version merge, and if both declarations set different credentials, compilation fails with a clear error instead of silently picking one.

Added regression tests verifying: multiple plugins (public + github-token + github-app) each get the correct, isolated token on their own checkout step; multiple github-app plugins each mint and reference their own distinct token step; credential preserved when a higher/lower version wins the merge; conflicting credentials on duplicate declarations are rejected.

@github-actions

Copy link
Copy Markdown
Contributor

Comment Memory

reviewed_at: 2026-08-28T00:00:00Z
review_event: REQUEST_CHANGES
top_themes:
  - plugin auth metadata lost during duplicate plugin dedupe
files_reviewed:
  - .github/workflows/agentic_commands.yml
  - docs/src/content/docs/reference/frontmatter.md
  - pkg/parser/schemas/main_workflow_schema.json
  - pkg/workflow/compiler_orchestrator_frontmatter.go
  - pkg/workflow/compiler_yaml_ai_execution.go
  - pkg/workflow/frontmatter_parsing.go
  - pkg/workflow/frontmatter_types.go
  - pkg/workflow/plugin_installation.go
  - pkg/workflow/plugins_engine_auth_integration_test.go
  - pkg/workflow/plugins_frontmatter.go
  - pkg/workflow/plugins_frontmatter_test.go
  - pkg/workflow/plugins_ref_resolution.go
  - pkg/workflow/plugins_test.go
  - pkg/workflow/workflow_builder.go
  - pkg/workflow/workflow_builder_frontmatter_extract.go
  - pkg/workflow/workflow_builder_test.go
  - pkg/workflow/workflow_data.go
comment_count: 1

Note

This comment is managed by comment memory.

It stores persistent context for this thread in the code block at the top of this comment.
Edit only the text inside the backtick fences; workflow metadata and the footer are regenerated automatically.

Learn more about comment memory

🔎 Code quality review by PR Code Quality Reviewer · pi · gpt54 · 46.3 AIC · ⌖ 7.44 AIC · ⊞ 7K ·
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.

REQUEST_CHANGES

This adds the right primitives for private plugin auth, but the merge/dedup path still drops auth metadata for duplicate plugin declarations, which makes the feature order-dependent and can compile a private plugin checkout without the intended credential.

The blocking theme
  • Duplicate plugins: entries with the same plugin/ref but different auth are currently treated as harmless duplicates instead of a conflict or an intentional override, so the surviving checkout token depends on declaration order.

🔎 Code quality review by PR Code Quality Reviewer · pi · gpt54 · 46.3 AIC · ⌖ 7.44 AIC · ⊞ 7K
Comment /review to run again

Comments that could not be inline-anchored

pkg/workflow/plugins_frontmatter.go:111

Per-plugin auth is silently discarded when the same plugin path is declared twice with different credentials but the same ref. mergeValidatedPluginRefs deduplicates only by repoPath and returns early on existing.ref == parsed.ref, so a main workflow entry can be overridden by an imported/public entry (or vice versa) without any error and the surviving checkout will use whichever credential appeared first. That makes private plugin installs fragile and order-dependent instead of determinis…

@github-actions

Copy link
Copy Markdown
Contributor

Warning

The push_to_pull_request_branch operation failed: Cannot push to pull request branch: bundle modifies files outside the allowed-files list (pkg/workflow/plugins_frontmatter.go, pkg/workflow/plugins_test.go). Add the files to the allowed-files configuration field or remove them from the bundle.. The code changes were not applied.

🏗️ ADR required — draft added for this implementation change

I enforced the design-decision gate for this PR because the prefetch summary shows 773 added lines in business-logic directories, which exceeds the default ADR threshold, even though the PR does not have the implementation label.

Evidence reviewed

  • PR title/body: "Support authenticated Agent Plugin installation from private repositories"
  • Linked issue: Support authenticated Agent Plugin installation from private repositories #55775 describes the expected plugins: object form with per-plugin github-token / github-app
  • Diff touches core compiler and workflow code, including:
    • pkg/workflow/plugins_frontmatter.go
    • pkg/workflow/plugin_installation.go
    • pkg/workflow/compiler_yaml_ai_execution.go
    • pkg/workflow/frontmatter_types.go
    • pkg/parser/schemas/main_workflow_schema.json
    • docs/src/content/docs/reference/frontmatter.md

Gate result

No existing Michael Nygard ADR was present in the PR body, linked issue, or current docs/adr/ branch state for this decision. The implementation clearly introduces an architectural decision: supporting authenticated private plugin installation through structured per-plugin credentials handled in shared compiler logic.

Action taken

I added a draft ADR at:

  • docs/adr/56505-support-authenticated-agent-plugin-installation.md

Next action for the author

Please review and refine that ADR, especially the decision rationale and trade-offs, before merging this PR.

Warning

Firewall blocked 1 domain

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

  • proxy.golang.org

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

network:
  allowed:
    - defaults
    - "proxy.golang.org"

See Network Configuration for more information.

🏗️ ADR gate enforced by Design Decision Gate 🏗️ · pi · gpt54 · 16.3 AIC · ⌖ 9.26 AIC · ⊞ 9.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.

pkg/workflow/plugin_installation.go:169: shrink: custom linesToActionSteps duplicates collapseYAMLLinesIntoSteps in checkout_step_generator.go. Reuse the existing helper or make the plugin path return the same []string form.

net: -12 lines possible.

Warning

Firewall blocked 4 domains

The following domains were blocked by the firewall during workflow execution:

  • ab.chatgpt.com
  • api.github.com
  • chatgpt.com
  • github.com

[!TIP]
api.github.com is blocked because GitHub API access uses the built-in GitHub tools by default. Instead of adding api.github.com to network.allowed, use tools.github.mode: gh-proxy for direct pre-authenticated GitHub CLI access without requiring network access to api.github.com:

tools:
  github:
    mode: gh-proxy

See GitHub Tools for more information on gh-proxy mode.

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

network:
  allowed:
    - defaults
    - "ab.chatgpt.com"
    - "api.github.com"
    - "chatgpt.com"
    - "github.com"

See Network Configuration for more information.

Generated by ✂️ Ponytail Reviewer for #56505 · codex · mai10 · 9.41 AIC · ⌖ 0.503 AIC · ⊞ 12.8K
Comment /ponytail to run again

Comment thread pkg/workflow/plugin_installation.go Outdated
return steps
}

// linesToActionSteps groups newline-terminated YAML step lines (as produced by

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.

pkg/workflow/plugin_installation.go:169: shrink: custom linesToActionSteps duplicates collapseYAMLLinesIntoSteps in checkout_step_generator.go. Reuse the existing helper or make the plugin path return the same []string form.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Resolved in c1f9c39: the bespoke YAML step splitter was removed; the mint-step output is emitted as one action step.

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

Review: Support authenticated Agent Plugin installation from private repositories

Overall the approach is well-structured and mirrors the existing SkillReference pattern closely. Two blocking issues were found:

🔴 Blocking

  1. Credential loss during semver deduplication (plugins_frontmatter.go mergeValidatedPluginRefs): when two declarations for the same repo use different semver tags and the winning (higher) one has no credential while the losing one does, the credential is silently dropped. See inline comment.

  2. Fragile YAML-line splitting (plugin_installation.go linesToActionSteps): step boundaries are detected by a hardcoded 6-space " - " prefix. Any indentation change silently produces a corrupt lock file. See inline comment.

✅ Positives

  • Schema updated with oneOf to allow both string and object entries, with proper additionalProperties: false.
  • Mutual exclusivity of github-token and github-app is validated early (frontmatter validation stage).
  • validatePluginSupport still gates the feature behind engine capability, so unsupported engines get a clear error.
  • Integration test covers all four engines (copilot, claude, codex, custom behavior-defined).
  • pluginTokenExpression gracefully handles the shouldIgnoreMissingKey case with token fallback.

🧵 Reviewed using Impeccable skills by Impeccable Skills Reviewer · copilot · sonnet46 · 39 AIC · ⌖ 10.8 AIC · ⊞ 6.2K

Comments that could not be inline-anchored

pkg/workflow/plugins_frontmatter.go:113

Credential loss during semver deduplication — when the same plugin repo is declared twice with different semver tags (e.g. v1 with a github-token and v2 without one), the higher-version ref entirely replaces the lower-version entry:

if semverutil.Compare(parsed.ref, existing.ref) &gt; 0 {
    merged[index] = ref   // ref may have no credentials
}

If the lower-version declaration carried the credential and the higher-version one did not, the token is silently dropped and t…

pkg/workflow/plugin_installation.go:175

Fragile YAML-line prefix in linesToActionSteps — this function detects step boundaries by matching the hardcoded string &quot; - &quot; (6 spaces + - ). This will silently mis-split or merge steps if the YAML indentation ever changes (e.g. a different job-level indent), producing a corrupted lock file without any error.

The function is only ever called with output from buildGitHubAppTokenMintStepWithMeta; consider either:

  • asserting/documenting the exact indent contract, or
  • passing t…

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

Adds per-plugin authentication for private Agent Plugin checkouts.

Changes:

  • Introduces structured plugin references with token or GitHub App credentials.
  • Generates authenticated checkout and GitHub App token steps.
  • Extends validation, schema, documentation, and tests.
Show a summary per file
File Description
pkg/workflow/workflow_data.go Stores structured plugin references.
pkg/workflow/workflow_builder.go Builds merged plugin references.
pkg/workflow/workflow_builder_test.go Updates builder tests.
pkg/workflow/workflow_builder_frontmatter_extract.go Extracts and merges structured entries.
pkg/workflow/plugins_test.go Tests authenticated compilation.
pkg/workflow/plugins_ref_resolution.go Keeps references synchronized after pinning.
pkg/workflow/plugins_frontmatter.go Adds parsing, validation, and deduplication.
pkg/workflow/plugins_frontmatter_test.go Tests object-form frontmatter.
pkg/workflow/plugins_engine_auth_integration_test.go Tests authentication across engines.
pkg/workflow/plugin_installation.go Generates token and authenticated checkout steps.
pkg/workflow/frontmatter_types.go Supports heterogeneous plugin entries.
pkg/workflow/frontmatter_parsing.go Parses structured plugin references.
pkg/workflow/compiler_yaml_ai_execution.go Emits plugin authentication steps.
pkg/workflow/compiler_orchestrator_frontmatter.go Invokes plugin validation.
pkg/parser/schemas/main_workflow_schema.json Adds object-form schema support.
docs/src/content/docs/reference/frontmatter.md Documents private plugin authentication.
.github/workflows/agentic_commands.yml Contains unrelated command-routing drift.

Review details

Suppressed comments (1)

pkg/workflow/plugins_frontmatter.go:118

  • When an authenticated main-workflow plugin is merged with a higher compatible version from an import, ref is the import's auth-free reference and this replacement discards the main workflow credential. The resulting private checkout falls back to github.token. Inherit the existing credential whenever the winning higher-version reference has no credential of its own.
func mergePluginRefAuth(target *PluginReference, incoming PluginReference) error {
	if !pluginRefHasAuth(incoming) {
  • Files reviewed: 17/17 changed files
  • Comments generated: 4
  • Review effort level: Balanced

Comment thread pkg/workflow/plugin_installation.go Outdated
Comment on lines +151 to +165
var steps []GitHubActionStep
for i, ref := range workflowData.PluginReferences {
if ref.GitHubApp == nil {
continue
}
lines := c.buildGitHubAppTokenMintStepWithMeta(
ref.GitHubApp,
nil,
"",
"",
fmt.Sprintf("Generate GitHub App token for agent plugin %d", i+1),
pluginAppTokenStepID(i),
)
steps = append(steps, linesToActionSteps(lines)...)
}

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed in 6addd0f: GitHub App token minting now derives the plugin owner and repository name, while explicit configuration still takes precedence.

Comment on lines +107 to 110
existing := parseSkillRefSpec(merged[index].Plugin)
if existing.ref == parsed.ref {
continue
}

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Resolved in cb15d74: duplicate plugin declarations preserve a lone credential and reject conflicting credentials.

Comment on lines +2467 to +2471
{
"type": "object",
"description": "Object-form plugin reference with per-plugin authentication.",
"required": ["plugin"],
"additionalProperties": false,

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed in 6addd0f: imported object-form plugin entries now retain their structured credentials through ImportsResult and workflow assembly, with regression coverage.

# /tidy -> tidy [pull_request_comment] reaction=eyes
# /unbloat -> unbloat-docs [pull_request_comment] reaction=eyes
# /wiki -> wiki [discussion,discussion_comment,issue_comment,issues,pull_request,pull_request_comment,pull_request_review_comment] reaction=eyes
# /windows -> windows [discussion,discussion_comment,issue_comment,issues,pull_request,pull_request_comment,pull_request_review_comment] reaction=eyes

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Resolved in c1f9c39: the unrelated generated command-routing drift was reverted.

@github-actions

Copy link
Copy Markdown
Contributor

🧪 Test Quality Sentinel Analysis

PR: Support authenticated Agent Plugin installation from private repositories (#56505)


Summary

Test Quality Score: 88/100 ✅ Excellent

This PR introduces well-structured tests for authenticated plugin installation across multiple agentic engines. The test suite demonstrates strong design coverage with proper error-path validation and multi-engine integration testing.


Key Metrics

Metric Value
Total Tests Added 16 test cases (via table-driven and subtests)
Test Functions 3 new behavioral tests
Coverage Model Integration + Unit hybrid
Build Tag Compliance ✅ 100% (proper (go/redacted):build tags)
Mock Policy Violations ✅ 0 (no gomock or testify/mock)
Assertion Quality ✅ High (descriptive error messages)
Design Contract Tests ✅ 14/16 behavioral
Implementation Detail Tests ⚠️ 2/16 parsing helpers
Test Inflation Ratio ✅ 1.1:1 (well-balanced)

Behavioral Test Breakdown

New Test Functions (Classified)

Integration Tests ((go/redacted):build integration)

TestPrivatePluginAuthAcrossEngines — Full-compile workflow for 4 engines

  • Design Contract: ✅ Behavioral — Verifies plugin auth tokens are correctly injected into compiled workflow YAML
  • Value: High — Catches regression if token injection breaks across any supported engine
  • Subtests:
    1. Copilot + github-token → 2 assertions (checkout step, token reference)
    2. Claude + github-token → 2 assertions (checkout step, token reference)
    3. Codex + github-token → 2 assertions (checkout step, token reference)
    4. Custom behavior-defined engine + github-token → 3 assertions (checkout, staging steps)
    5. Copilot + github-app → 3 assertions (app token generation, checkout step, token output reference)
    6. Claude + github-app → 3 assertions
    7. Codex + github-app → 3 assertions

Edge Cases Covered:

  • ✅ Both authentication methods (token + app)
  • ✅ Multiple engine types (3 first-party + custom)
  • ✅ Workflow compilation with temporary directories
  • ✅ Lock file output verification

Unit Tests ((go/redacted):build !integration)

TestValidateFrontmatterPlugins — Frontmatter schema validation

  • Design Contract: ✅ Behavioral — Ensures plugin config is rejected/accepted per spec
  • Value: High — Guards against malformed plugin declarations
  • Subtests (11 test cases):
    1. ✅ Accepts simple string form: "octo-org/plugin@ref"
    2. ✅ No-op without plugins field (idempotent)
    3. ❌ Rejects non-array plugins field
    4. ✅ Accepts object form with github-token
    5. ❌ Rejects steps-output tokens (security boundary)
    6. ✅ Accepts object form with github-app
    7. ❌ Rejects github-token + github-app together (mutually exclusive)
    8. ❌ Rejects object missing required plugin field
    9. ❌ Rejects github-app missing private-key
    10. ❌ Rejects unknown fields (bogus)
    11. ❌ Rejects non-string/non-object entries

Error Coverage: ✅ 9/11 subtests validate error paths (strong negative testing)

TestParseRawPluginReferences — Plugin reference parsing

  • Design Contract: ⚠️ Implementation detail — Verifies internal parser logic
  • Value: Medium — Ensures auth fields are parsed correctly; could be covered by integration test
  • Assertions: 8 assertions covering:
    • String-form plugin references (no auth)
    • Object-form with github-token
    • Object-form with github-app (client-id + private-key)

Quality Signals

Strengths:

  • Proper build tags: All files correctly declare (go/redacted):build !integration or (go/redacted):build integration
  • Error-path focus: 10+ distinct error scenarios tested (required fields, type validation, mutual exclusivity)
  • Multi-engine coverage: Integration test covers 4 engine variants (Copilot, Claude, Codex, custom) to catch engine-specific breakage
  • No mock library violations: Uses only require/assert from testify (safe pattern)
  • Descriptive assertions: Error messages include field names (plugins[0].github-token, mutually exclusive)
  • Realistic workflows: Integration tests compile actual markdown workflows and inspect YAML output

⚠️ Observations:

  • TestParseRawPluginReferences tests internal parsing logic that overlaps with validation tests; could be considered implementation detail but is useful for parser regression detection
  • Test file size (153 + 142 = 295 lines) vs. production changes (~250 lines production code) yields ~1.1:1 ratio (healthy, not inflated)

Scoring Breakdown

Design-test ratio:     14/16 = 87.5% → 35.0 points
Edge-case coverage:    10/16 error paths → 30.0 points
Duplicate patterns:    0 clusters → 20.0 points
Inflation ratio:       1.1:1 → 10.0 points (no penalty)
────────────────────────────────────
Final Score:           88/100 ✅

Next Steps

Approval: No violations detected. All tests are well-designed behavioral tests with proper build tags, error coverage, and no mock-library violations.

Recommendations (non-blocking):

  1. Consider collapsing TestParseRawPluginReferences into a table-driven test within integration tests for simpler maintenance
  2. Add a comment documenting testAuthPluginSHA usage for future contributors

Warning

Firewall blocked 1 domain

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

  • github.com

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

network:
  allowed:
    - defaults
    - "github.com"

See Network Configuration for more information.

🧪 Test quality analysis by Test Quality Sentinel · copilot · haiku45 · 24 AIC · ⌖ 10.4 AIC · ⊞ 8.3K ·
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: 88/100 Excellent.

87.5% design tests, 10+ error-path scenarios covered, 0 mock-library violations, proper build tags.

Strong multi-engine integration testing with proper authentication validation. No issues 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 /codebase-design and /tdd — requesting changes on two correctness issues and two test-coverage gaps.

📋 Key Themes & Highlights

Key Themes

  1. Fragile YAML line-splitting (linesToActionSteps): the " - " prefix heuristic is a bespoke sub-parser that could mis-split steps if a with: value contains that prefix. The root cause is that buildGitHubAppTokenMintStepWithMeta returns []string rather than []GitHubActionStep.

  2. Silent credential drop in dedup (mergeValidatedPluginRefs): when the same plugin+ref is declared twice with different github-token values, the second credential is silently discarded. This is a correctness and potential security hazard — the author may believe their override is active when it isn't.

  3. Implicit positional coupling between workflowData.Plugins and workflowData.PluginReferences: generatePluginInstallationSteps iterates the string slice and looks up credentials by the same integer index into the references slice. The invariant is maintained by validatePlugins, but it's an implicit contract that future callers can easily break.

  4. Integration test assertions are weak: assert.Contains(t, lockText, "token: ...") confirms the token string exists in the lock file but not that it's on the correct step.

Positive Highlights

  • ✅ Excellent parity with the existing SkillReference pattern — the PR is consistent and well-modelled.
  • ✅ Good backward compatibility: string-only plugins still work without any configuration change.
  • ✅ Strong unit test coverage for validateFrontmatterPlugins and pluginTokenExpression.
  • ✅ Engine-agnostic auth injection is a clean design decision — no per-engine changes needed.
  • pluginReferencesOrFallback is a good defensive helper for callers that only populate Plugins.

🧠 Reviewed using Matt Pocock's skills by Matt Pocock Skills Reviewer · copilot · sonnet46 · 65 AIC · ⌖ 11 AIC · ⊞ 7.6K
Comment /matt to run again

Comments that could not be inline-anchored

pkg/workflow/plugin_installation.go:177

[/codebase-design] linesToActionSteps splits a []string of YAML lines by detecting &quot; - &quot; as a step boundary. This is a fragile heuristic: any with: value containing that exact prefix would incorrectly start a new step. All other step-builders in this file return GitHubActionStep directly.

<details>
<summary>💡 Suggested fix</summary>

If buildGitHubAppTokenMintStepWithMeta always returns one logical step, simply wrap it:

steps = append(steps, GitHubActionStep(lines)…

</details>

<details><summary>pkg/workflow/plugins_frontmatter.go:108</summary>

**[/codebase-design]** When `mergeValidatedPluginRefs` deduplicates two entries with **the same ref** (`existing.ref == parsed.ref`) but **different `github-token` values**, the second credential is silently droppedthe first one wins. There&#39;s no warning to the author that a declared credential was ignored.

&lt;details&gt;
&lt;summary&gt;💡 Suggested fix&lt;/summary&gt;

Either error when credentials conflict:

```go
if existing.ref == parsed.ref {
    if merged[index].GitHubToken != ref.GitHubToken || !appCo…

</details>

<details><summary>pkg/workflow/plugin_installation.go:202</summary>

**[/codebase-design]** `generatePluginInstallationSteps` iterates `workflowData.Plugins` (the plain-string slice) at line 202 but looks up credentials via `pluginTokenExpression(workflowData, i)` which indexes into `workflowData.PluginReferences` by the same integer `i`. This positional coupling means the two slices **must stay in sync** — and `validatePlugins` arranges that, but the contract is implicit.

&lt;details&gt;
&lt;summary&gt;💡 Suggested fix&lt;/summary&gt;

Iterate `PluginReferences` directly (since…

</details>

<details><summary>pkg/workflow/plugins_engine_auth_integration_test.go:76</summary>

**[/tdd]** The integration test asserts that `token: ${{ secrets.PRIVATE_PLUGIN_TOKEN }}` appears *somewhere* in the lock file, but doesn&#39;t verify it appears in the correct checkout step. If the token were accidentally emitted in a different step (e.g., a staging command), the test would still pass.

&lt;details&gt;
&lt;summary&gt;💡 Suggested fix&lt;/summary&gt;

Assert on adjacent lines to confirm placement:

```go
assert.Regexp(t, `(?s)name: Checkout agent plugin octo-org/private-plugin.*?token: \$\{\{ secret…

</details>

<details><summary>pkg/workflow/plugins_frontmatter.go:108</summary>

**[/tdd]** There are no unit tests for `mergeValidatedPluginRefs` covering the case where the same plugin is listed twice with **different credentials** but the same ref. The `continue` path at line 108 silently drops the second credential — this edge case should have an explicit test to document (and, once the bug above is addressed, to enforce) the intended behavior.

&lt;details&gt;
&lt;summary&gt;💡 Suggested test skeleton&lt;/summary&gt;

```go
t.Run(&quot;errors when same plugin ref is declared twice with diffe…

</details>

@pelikhan

Copy link
Copy Markdown
Collaborator

@copilot run pr-finisher skill

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

Copilot AI commented Aug 28, 2026

Copy link
Copy Markdown
Contributor Author

@copilot run pr-finisher skill

Ran the PR-finisher pass and pushed c1f9c39. Local validation is complete; remaining CI must be re-triggered by a maintainer.

@gh-aw-bot

Copy link
Copy Markdown
Collaborator

@copilot Remaining review feedback still needs resolution on this PR.

Please address the unresolved items, then run the pr-finisher skill:

Generated by 👨‍🍳 PR Sous Chef · pi · gpt54 · 31.3 AIC · ⌖ 8.76 AIC · ⊞ 8.8K ·
Comment /souschef to run again

Copilot AI and others added 2 commits August 28, 2026 13:46
Co-authored-by: gh-aw-bot <259018956+gh-aw-bot@users.noreply.github.com>
Co-authored-by: gh-aw-bot <259018956+gh-aw-bot@users.noreply.github.com>

Copilot AI commented Aug 28, 2026

Copy link
Copy Markdown
Contributor Author

@copilot Remaining review feedback still needs resolution on this PR.

Please address the unresolved items, then run the pr-finisher skill:...

Addressed the listed feedback and ran the PR-finisher validation. The latest commit is 6addd0f.

Copilot AI requested a review from gh-aw-bot August 28, 2026 14:06
@pelikhan
pelikhan merged commit c4bc45e into main Aug 28, 2026
34 checks passed
@pelikhan
pelikhan deleted the copilot/support-authenticated-agent-plugin-installation branch August 28, 2026 16:21
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.

Support authenticated Agent Plugin installation from private repositories

4 participants