Commit a1c795b
Replace Playwright MCP server with Playwright CLI installation (#14569)
* Replace Playwright MCP server with Playwright CLI installation
Replace the Playwright MCP server configuration in `aspire agent init` with a
secure Playwright CLI installation workflow. Instead of writing MCP server
configuration to each agent environment's config file, the new approach:
- Resolves the @playwright/cli package version from npm registry
- Downloads the package tarball via `npm pack`
- Verifies supply chain integrity (SHA-512 SRI hash comparison)
- Runs `npm audit signatures` for provenance verification
- Installs globally from the verified tarball
- Runs `playwright-cli install --skills` to generate skill files
New abstractions:
- INpmRunner/NpmRunner: npm CLI command runner (resolve, pack, audit, install)
- IPlaywrightCliRunner/PlaywrightCliRunner: playwright-cli command runner
- PlaywrightCliInstaller: orchestrates the secure install flow
This removes ~400 lines of per-scanner MCP config writing code (different JSON
formats for VS Code, Claude Code, Copilot CLI, and OpenCode) and replaces it
with a single global CLI install.
Fixes #14430
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Pin Playwright CLI version range to 0.1.1
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Add npm provenance verification and break-glass config
- Add INpmProvenanceChecker/NpmProvenanceChecker for SLSA attestation verification
- Return rich ProvenanceVerificationResult with gate-specific outcome enum
- Fix AuditSignaturesAsync with temp-project approach for global tools
- Add disablePlaywrightCliPackageValidation break-glass config option
- Add security design document (docs/specs/safe-npm-tool-install.md)
- Verify SRI integrity, Sigstore attestations, and source repository provenance
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Fix markdownlint: add language to fenced code block
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Improve version resolution and provenance verification
- Change version range from exact 0.1.1 to >=0.1.1 for future versions
- Add playwrightCliVersion config override for pinning specific versions
- Verify workflow path (.github/workflows/publish.yml) in provenance
- Verify SLSA build type (GitHub Actions) to confirm OIDC token issuer
- Add BuildType to NpmProvenanceData, WorkflowMismatch and
BuildTypeMismatch outcomes
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Add tests for version pinning and default version range
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Add E2E test for Playwright CLI installation via agent init
Verifies the full lifecycle: project creation, aspire agent init with
Claude Code environment, Playwright CLI installation with npm provenance
verification, and skill file generation.
Marked as OuterloopTest since it requires npm and network access.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Show status spinner during Playwright CLI installation
Wrap the installation work in IInteractionService.ShowStatusAsync to
display a spinner with 'Installing Playwright CLI...' status text while
the npm operations are in progress.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Mirror playwright-cli skill files to all detected agent environments
After playwright-cli install --skills creates files in .claude/skills/,
the installer now mirrors the playwright-cli skill directory to all
other detected agent environment skill directories (.github/skills/,
.opencode/skill/, etc.) so every configured environment has identical
skill files. Stale files in target directories are also removed.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Update security design doc to match implementation
- Step 4 now documents all three provenance gates: source repository,
workflow path, and build type (with OIDC issuer implication)
- Added table of verified fields with expected values
- Updated implementation constants to include new fields
- Added configuration section documenting break-glass keys
- Updated verification diagram with workflow/build type checks
- Step 7 now documents skill file mirroring across environments
- Future improvements reflects experimental Sigstore branch status
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Verify workflow ref matches package version in provenance
Add Gate 6 to provenance verification: check that the workflow ref
(git tag) in the SLSA attestation matches refs/tags/v{version}. This
ensures the build was triggered from the expected release tag, not
an arbitrary branch or commit.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Use callback-based workflow ref validation in provenance checker
Make the workflow ref validation configurable per-package by accepting a
Func<WorkflowRefInfo, bool> callback instead of hardcoding the
refs/tags/v{version} format. The ref is parsed into a WorkflowRefInfo
record (Raw, Kind, Name) and the caller decides what's valid.
PlaywrightCliInstaller validates Kind=tags and Name=v{version}.
Other packages can use different tag conventions without modifying
the provenance checker.
Addresses review feedback from DamianEdwards.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Replace npm provenance checking with Sigstore verification
Use the Sigstore and Tuf NuGet packages (0.2.0) to cryptographically
verify npm attestation bundles in-process, replacing the previous
approach of shelling out to 'npm audit signatures'.
- Add SigstoreNpmProvenanceChecker implementing INpmProvenanceChecker
using SigstoreVerifier with CertificateIdentity.ForGitHubActions
- Remove the npm audit signatures step from PlaywrightCliInstaller
- Keep existing NpmProvenanceChecker but no longer register in DI
- Add optional sriIntegrity parameter to INpmProvenanceChecker for
digest-based bundle verification
- Update safe-npm-tool-install.md spec to reflect new verification flow
- Temporarily add nuget.org to NuGet.config for Sigstore/Tuf packages
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Refactor SigstoreNpmProvenanceChecker for clarity
Break the monolithic VerifyProvenanceAsync method into focused methods:
- FetchAttestationJsonAsync: fetches attestation JSON from npm registry
- ParseAttestation: parses JSON in a single pass, extracting both the
Sigstore bundle and provenance data (eliminates duplicate JSON parsing)
- ParseProvenanceFromStatement: extracts provenance fields from in-toto statement
- VerifySigstoreBundleAsync: cryptographic Sigstore verification
- VerifyProvenanceFields: field-level provenance checks (source repo,
workflow, build type, workflow ref)
Removes dependency on NpmProvenanceChecker.ParseProvenance() which was
re-parsing the same JSON and iterating attestations a second time.
Adds NpmAttestationParseResult type to carry both bundle and provenance
data from a single parse pass.
Adds comprehensive unit tests for ParseAttestation, ParseProvenanceFromStatement,
and VerifyProvenanceFields covering success and failure cases.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Add libsodium to nuget-org package source mapping
libsodium is a transitive dependency of NSec.Cryptography (used by Sigstore)
and needs to be mapped to the nuget-org source for CI restore to succeed.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---------
Co-authored-by: Mitch Denny <mitch@mitchdeny.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>1 parent 7182c6a commit a1c795b
File tree
44 files changed
+3603
-392
lines changed- docs/specs
- src/Aspire.Cli
- Agents
- ClaudeCode
- CopilotCli
- OpenCode
- Playwright
- VsCode
- Npm
- Resources
- xlf
- tests
- Aspire.Cli.EndToEnd.Tests
- Aspire.Cli.Tests
- Agents
- TestServices
Some content is hidden
Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
44 files changed
+3603
-392
lines changed| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
132 | 132 | | |
133 | 133 | | |
134 | 134 | | |
| 135 | + | |
| 136 | + | |
135 | 137 | | |
136 | 138 | | |
137 | 139 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
20 | 20 | | |
21 | 21 | | |
22 | 22 | | |
| 23 | + | |
| 24 | + | |
23 | 25 | | |
24 | 26 | | |
25 | 27 | | |
| |||
43 | 45 | | |
44 | 46 | | |
45 | 47 | | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
46 | 55 | | |
47 | 56 | | |
48 | 57 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
| 125 | + | |
| 126 | + | |
| 127 | + | |
| 128 | + | |
| 129 | + | |
| 130 | + | |
| 131 | + | |
| 132 | + | |
| 133 | + | |
| 134 | + | |
| 135 | + | |
| 136 | + | |
| 137 | + | |
| 138 | + | |
| 139 | + | |
| 140 | + | |
| 141 | + | |
| 142 | + | |
| 143 | + | |
| 144 | + | |
| 145 | + | |
| 146 | + | |
| 147 | + | |
| 148 | + | |
| 149 | + | |
| 150 | + | |
| 151 | + | |
| 152 | + | |
| 153 | + | |
| 154 | + | |
| 155 | + | |
| 156 | + | |
| 157 | + | |
| 158 | + | |
| 159 | + | |
| 160 | + | |
| 161 | + | |
| 162 | + | |
| 163 | + | |
| 164 | + | |
| 165 | + | |
| 166 | + | |
| 167 | + | |
| 168 | + | |
| 169 | + | |
| 170 | + | |
| 171 | + | |
| 172 | + | |
| 173 | + | |
| 174 | + | |
| 175 | + | |
| 176 | + | |
| 177 | + | |
| 178 | + | |
| 179 | + | |
| 180 | + | |
| 181 | + | |
| 182 | + | |
| 183 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
10 | 10 | | |
11 | 11 | | |
12 | 12 | | |
| 13 | + | |
13 | 14 | | |
14 | 15 | | |
15 | 16 | | |
| |||
24 | 25 | | |
25 | 26 | | |
26 | 27 | | |
27 | | - | |
| 28 | + | |
28 | 29 | | |
29 | 30 | | |
30 | 31 | | |
31 | 32 | | |
32 | | - | |
33 | | - | |
34 | | - | |
35 | | - | |
36 | | - | |
37 | | - | |
38 | | - | |
39 | | - | |
40 | | - | |
41 | | - | |
42 | | - | |
43 | | - | |
44 | | - | |
45 | | - | |
46 | | - | |
47 | | - | |
48 | | - | |
49 | | - | |
50 | | - | |
51 | | - | |
52 | 33 | | |
53 | 34 | | |
54 | 35 | | |
| |||
82 | 63 | | |
83 | 64 | | |
84 | 65 | | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
85 | 81 | | |
0 commit comments