Skip to content

Commit 0ad3d22

Browse files
authored
feat(smoke): run agentic smoke against compiler candidates (#1628)
* feat(smoke): run agentic smoke against compiler candidates Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: a7017732-e510-4ed3-84fb-47ce7120230e * refactor(compile): address pipeline artifact review feedback Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: a7017732-e510-4ed3-84fb-47ce7120230e * fix(smoke): align candidate integrity metadata Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: a7017732-e510-4ed3-84fb-47ce7120230e * chore(smoke): add AgentPlayground secret rotation script Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: a7017732-e510-4ed3-84fb-47ce7120230e * fix(smoke): keep release pipelines off pull requests Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: a7017732-e510-4ed3-84fb-47ce7120230e
1 parent 4fe59c7 commit 0ad3d22

56 files changed

Lines changed: 7014 additions & 638 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

AGENTS.md

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -342,10 +342,11 @@ index to jump to the right page.
342342
issues from dogfood pipelines). NOT a regular safe-output.
343343
- [`docs/supply-chain.md`](docs/supply-chain.md) — optional `supply-chain:`
344344
front-matter section that mirrors the compiler, AWF binary, ado-script
345-
bundle, and AWF/MCPG images from an internal Azure DevOps Artifacts feed
346-
and/or container registry (NuGet `DownloadPackage@1` + ACR `az acr login`),
347-
with asymmetric auth (feed defaults to `$(System.AccessToken)`; registry
348-
requires a service connection).
345+
bundle, and AWF/MCPG images from an internal Azure DevOps Artifacts feed,
346+
an exact provenance-checked pipeline artifact, and/or a container registry.
347+
Feed and pipeline artifact are mutually exclusive; registry is independent.
348+
Feed defaults to `$(System.AccessToken)`, while registry requires a service
349+
connection and the pipeline artifact uses the build identity.
349350

350351
### Compiler internals & operations
351352

@@ -442,8 +443,8 @@ Following the gh-aw security model:
442443
`src/compile/agentic_pipeline.rs::run_agent_step`). AWF runs rootlessly in
443444
strict topology mode; the Agent reaches trusted MCPG through
444445
`--topology-attach awmg-mcpg`, not through host access. All other ADO steps —
445-
binary/bundle downloads, `docker pull`, ACR/NuGet auth (including the
446-
`supply-chain:` mirror fetches) — run *outside* the sandbox with the build
446+
binary/bundle downloads, `docker pull`, ACR/NuGet auth (including feed and
447+
pipeline-artifact `supply-chain:` fetches) — run *outside* the sandbox with the build
447448
agent pool's normal network, so they do **not** need entries in the AWF
448449
allowlist. Air-gapping the build agent itself from GitHub/GHCR is the agent
449450
pool's network policy, not AWF.
@@ -496,6 +497,17 @@ anything it flags. If a finding is genuinely intentional, add a
496497
`# shellcheck disable=SCxxxx` comment immediately above the offending line in
497498
the bash body — shellcheck honours the directive and it's inert at runtime.
498499

500+
### Release-owned smoke lock files
501+
502+
`tests/safe-outputs/*.lock.yml` are the latest-release customer contract. Do
503+
not regenerate them with `cargo run -- compile` from an unreleased checkout:
504+
their runtime integrity step downloads the released compiler, so development
505+
output can drift even while Cargo still reports the same semver. Compiler PRs
506+
and nightly `main` are exercised by `tests/compiler-smoke-e2e/`, which
507+
recompiles all five workflows in a temporary worktree and stages them on an
508+
ephemeral `ado-aw-mirror` ref. The release workflow updates the checked-in
509+
locks only after matching release assets exist.
510+
499511
## Common Tasks
500512

501513
### Compile a markdown pipeline

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -729,7 +729,8 @@ index to jump to the right page.
729729
- [`docs/safe-output-permissions.md`](docs/safe-output-permissions.md)
730730
diagnosis and fix reference for Stage 3 permission failures (401/403).
731731
- [`docs/supply-chain.md`](docs/supply-chain.md) — optional `supply-chain:`
732-
front-matter section for internal feed/registry mirrors.
732+
front-matter section for internal feed/registry mirrors and exact
733+
provenance-checked pipeline artifacts.
733734
- [`docs/ado-aw-debug.md`](docs/ado-aw-debug.md) — debug-only `ado-aw-debug:`
734735
front-matter section (`skip-integrity`, `create-issue`).
735736

docs/front-matter.md

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -217,10 +217,15 @@ supply-chain: # optional internal supply-chain mirror (see docs
217217
feed: # mirror binaries (compiler, AWF, ado-script) from an ADO Artifacts feed
218218
name: my-project/my-feed # feed name or project/feed; scalar `feed: my-feed` shorthand also works
219219
service-connection: feed-conn # optional; omit for same-org feeds (uses $(System.AccessToken))
220+
# pipeline-artifact: # alternative binary source; mutually exclusive with feed
221+
# project: AgentPlayground # validated ADO project name or GUID
222+
# definition-id: 2560 # positive producer pipeline definition ID
223+
# run-id: 630001 # positive, exact producer build ID
224+
# artifact: ado-aw-candidate # complete payload/checksum/provenance artifact
220225
registry: # mirror AWF/MCPG images from an internal ACR
221226
name: myacr.azurecr.io/mirror # registry host or base path (artifact names kept under it)
222227
service-connection: acr-conn # REQUIRED when registry is set (ACR has no System.AccessToken path)
223-
service-connection: shared-conn # optional shared fallback for whichever target omits its own
228+
service-connection: shared-conn # optional feed/registry fallback; never applies to pipeline-artifact
224229
# ado-aw-debug: # debug-only knobs; see docs/ado-aw-debug.md
225230
# skip-integrity: false # omit generated pipeline integrity verification
226231
# create-issue: false # dogfood-only GitHub issue filing for debug reports

docs/supply-chain.md

Lines changed: 108 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,10 @@ GitHub / GHCR at run time:
1111
| 4 | AWF + MCPG container images | `ghcr.io/github/...` |
1212

1313
The optional `supply-chain:` front-matter section reroutes these fetches to an
14-
**internal Azure DevOps Artifacts feed** (for the binaries #1#3) and/or an
15-
**internal container registry** (for the images #4). This is intended for
16-
supply-chain-hardened environments where the build agent pool cannot reach
17-
GitHub / GHCR.
14+
**internal Azure DevOps Artifacts feed** or one exact **Azure DevOps pipeline
15+
artifact** (for the binaries #1#3), and/or an **internal container registry**
16+
(for the images #4). This is intended for supply-chain-hardened environments
17+
where the build agent pool cannot reach GitHub / GHCR.
1818

1919
When `supply-chain:` is omitted, the generated pipeline is byte-for-byte
2020
identical to before — there is no behavioural change for existing agents.
@@ -26,6 +26,12 @@ supply-chain:
2626
feed: # mirrors binaries #1, #2, #3
2727
name: my-project/my-feed # feed name or "project/feed"
2828
service-connection: feed-conn # optional (see Authentication)
29+
# Alternative to feed (the two are mutually exclusive):
30+
# pipeline-artifact:
31+
# project: AgentPlayground
32+
# definition-id: 2560
33+
# run-id: 630001
34+
# artifact: ado-aw-candidate
2935
registry: # mirrors images #4
3036
name: myacr.azurecr.io/mirror # registry host or base path
3137
service-connection: acr-conn # required when registry is set
@@ -35,10 +41,12 @@ supply-chain:
3541
| Field | Type | Required | Purpose |
3642
|-------|------|----------|---------|
3743
| `feed` | scalar **or** `{ name, service-connection }` | optional | Enables the binary mirror (#1–#3). A bare string is shorthand for `{ name: <string> }`. |
38-
| `registry` | scalar **or** `{ name, service-connection }` | optional | Enables the image mirror (#4). |
39-
| `service-connection` | string | optional | Shared fallback connection used by whichever target does not declare its own. |
44+
| `pipeline-artifact` | `{ project, definition-id, run-id, artifact }` | optional | Uses one exact producer run as the complete binary source (#1–#3). Mutually exclusive with `feed`. |
45+
| `registry` | scalar **or** `{ name, service-connection }` | optional | Enables the image mirror (#4), independently of either binary source. |
46+
| `service-connection` | string | optional | Shared fallback connection for `feed` and `registry`; it does not apply to `pipeline-artifact`. |
4047

41-
`feed` and `registry` are **independent** — set either, both, or neither.
48+
`feed` and `pipeline-artifact` are mutually exclusive. `registry` is
49+
independent and may accompany either binary source.
4250

4351
### Scalar shorthand
4452

@@ -71,6 +79,28 @@ role and `NuGetAuthenticate@1` authenticates automatically via
7179
`$(System.AccessToken)`. Set a `service-connection` only for cross-org or
7280
external feeds.
7381

82+
### Pipeline artifact (binaries)
83+
84+
The pipeline-artifact source is immutable configuration: the generated
85+
`DownloadPipelineArtifact@2` tasks always use `source: specific`,
86+
`runVersion: specific`, the configured project, definition ID (`pipeline`),
87+
run ID (`runId`), and artifact name. The compiler never selects latest runs,
88+
tags, or triggering pipelines.
89+
90+
`project` must be an Azure DevOps project name or canonical GUID;
91+
`definition-id` and `run-id` must be positive integers; and `artifact` follows
92+
Azure DevOps artifact-name rules. The current build identity must have
93+
permission to read the configured project, pipeline run, and artifact.
94+
The producer must be in the same Azure DevOps organization; cross-organization
95+
pipeline-artifact downloads are not supported by this source.
96+
`supply-chain.service-connection` is not used for this source, and no
97+
`NuGetAuthenticate@1` step is emitted.
98+
99+
With an exact run ID, the artifact is consumable as soon as its publish task
100+
has completed even if later jobs keep the producer run active. Consumers
101+
queued before the named artifact exists fail; producers should confirm artifact
102+
visibility before queueing them.
103+
74104
### Registry (images)
75105

76106
The image mirror authenticates with `az acr login` (`AzureCLI@2`) using the
@@ -96,7 +126,7 @@ used by `permissions:`), passed to `AzureCLI@2` as `azureSubscription`.
96126
> `registry.name` to the canonical `*.azurecr.io` login server so the derived
97127
> registry name is correct.
98128
99-
## What the feed and registry must contain
129+
## What the binary source and registry must contain
100130

101131
Versions stay **pinned by the generating compiler** — the internal mirror must
102132
host the exact pinned versions. A mirror that is a few days behind is fine: use
@@ -119,6 +149,47 @@ payload, so the package simply needs to carry the same files (and matching
119149
`sha256sum -c checksums.txt` is preserved**, so the mirror must ship the
120150
matching `checksums.txt`.
121151

152+
### Pipeline artifact
153+
154+
The single configured artifact is a complete source and must contain exactly
155+
one file with each of these names (directory nesting is allowed):
156+
157+
- `ado-aw-linux-x64`
158+
- `awf-linux-x64`
159+
- `ado-script.zip`
160+
- `checksums.txt`
161+
- `provenance.json`
162+
163+
`checksums.txt` must have exactly one standard sha256sum entry for each payload,
164+
with the exact filename. Each consumer locates its payload plus the shared
165+
manifest and provenance document, verifies the exact checksum entry, then
166+
preserves the normal chmod/move/unzip/PATH behavior.
167+
168+
`provenance.json` must be a JSON object using this Phase 1 contract:
169+
170+
```json
171+
{
172+
"schema": "ado-aw/candidate-artifact/1",
173+
"producer_definition_id": 2560,
174+
"producer_build_id": 630001,
175+
"repository": "githubnext/ado-aw",
176+
"source_ref": "refs/heads/main",
177+
"source_version": "0123456789abcdef0123456789abcdef01234567",
178+
"reason": "IndividualCI",
179+
"compiler_version": "0.45.1",
180+
"awf_version": "0.27.32"
181+
}
182+
```
183+
184+
The required identity fields are exactly `schema`, `producer_definition_id`,
185+
and `producer_build_id`; both producer IDs are JSON numbers. Compilation embeds
186+
the configured IDs, and every consumer fails closed if the schema or either
187+
producer ID is missing, non-numeric, or mismatched. `repository`, `source_ref`,
188+
`source_version`, `reason`, `compiler_version`, and `awf_version` are optional
189+
diagnostic fields: when present, the generated step includes them in the
190+
validated, non-secret provenance output. Their absence does not invalidate an
191+
otherwise valid artifact.
192+
122193
### Registry images
123194

124195
`registry.name` is a registry **host or base path** — teams generally cannot
@@ -175,6 +246,31 @@ supply-chain:
175246
feed: my-internal-feed
176247
```
177248

249+
All binaries from one exact candidate pipeline run:
250+
251+
```yaml
252+
supply-chain:
253+
pipeline-artifact:
254+
project: AgentPlayground
255+
definition-id: 2560
256+
run-id: 630001
257+
artifact: ado-aw-candidate
258+
```
259+
260+
Candidate binaries plus mirrored images:
261+
262+
```yaml
263+
supply-chain:
264+
pipeline-artifact:
265+
project: AgentPlayground
266+
definition-id: 2560
267+
run-id: 630001
268+
artifact: ado-aw-candidate
269+
registry:
270+
name: myacr.azurecr.io
271+
service-connection: acr-conn
272+
```
273+
178274
Images only:
179275

180276
```yaml
@@ -186,9 +282,10 @@ supply-chain:
186282

187283
## Network isolation note
188284

189-
The mirror fetches (`NuGetAuthenticate@1`, `DownloadPackage@1`, `docker pull`,
190-
`az acr login`) run as ordinary ADO steps on the build agent — **outside** the
191-
AWF network-isolation sandbox, which wraps only the copilot agent command.
285+
The mirror fetches (`NuGetAuthenticate@1`, `DownloadPackage@1`,
286+
`DownloadPipelineArtifact@2`, `docker pull`, `az acr login`) run as ordinary
287+
ADO steps on the build agent — **outside** the AWF network-isolation sandbox,
288+
which wraps only the copilot agent command.
192289
Consequently:
193290

194291
- The feed/registry hosts are **not** added to the agent's AWF

rotate-agentplayground-secrets.ps1

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
[CmdletBinding()]
2+
param(
3+
[string] $Organization = "msazuresphere",
4+
[string] $Project = "AgentPlayground"
5+
)
6+
7+
Set-StrictMode -Version Latest
8+
$ErrorActionPreference = "Stop"
9+
10+
$copilotDefinitionIds = @(2545, 2546, 2547, 2548, 2549, 2554, 2555, 2556, 2557, 2558)
11+
$reporterDefinitionIds = @(2549, 2558)
12+
$executorDefinitionIds = @(2550)
13+
$triggerDefinitionIds = @(2551)
14+
$allDefinitionIds = @(
15+
$copilotDefinitionIds
16+
$executorDefinitionIds
17+
$triggerDefinitionIds
18+
) | Sort-Object -Unique
19+
20+
function Set-AdoAwSecret {
21+
param(
22+
[Parameter(Mandatory)]
23+
[string] $Name,
24+
25+
[Parameter(Mandatory)]
26+
[string] $Value,
27+
28+
[Parameter(Mandatory)]
29+
[int[]] $DefinitionIds
30+
)
31+
32+
Write-Host "Setting $Name on definitions $($DefinitionIds -join ',')..."
33+
$Value | & cargo run --quiet -- secrets set $Name --value-stdin `
34+
--org $Organization `
35+
--project $Project `
36+
--definition-ids ($DefinitionIds -join ",")
37+
38+
if ($LASTEXITCODE -ne 0) {
39+
throw "Failed to set $Name on definitions $($DefinitionIds -join ',')."
40+
}
41+
}
42+
43+
Push-Location $PSScriptRoot
44+
try {
45+
$copilotToken = Read-Host "New Copilot GITHUB_TOKEN" -MaskInput
46+
if ([string]::IsNullOrWhiteSpace($copilotToken)) {
47+
throw "The Copilot GITHUB_TOKEN cannot be empty."
48+
}
49+
50+
Set-AdoAwSecret `
51+
-Name "GITHUB_TOKEN" `
52+
-Value $copilotToken `
53+
-DefinitionIds $copilotDefinitionIds
54+
55+
Remove-Variable copilotToken
56+
57+
$issuesToken = Read-Host `
58+
"New issues-only GitHub PAT (leave blank to preserve existing issue tokens)" `
59+
-MaskInput
60+
61+
if ([string]::IsNullOrWhiteSpace($issuesToken)) {
62+
Write-Host "Preserving existing issue-reporting tokens."
63+
}
64+
else {
65+
Set-AdoAwSecret `
66+
-Name "ADO_AW_DEBUG_GITHUB_TOKEN" `
67+
-Value $issuesToken `
68+
-DefinitionIds $reporterDefinitionIds
69+
70+
Set-AdoAwSecret `
71+
-Name "EXECUTOR_E2E_GITHUB_TOKEN" `
72+
-Value $issuesToken `
73+
-DefinitionIds $executorDefinitionIds
74+
75+
Set-AdoAwSecret `
76+
-Name "TRIGGER_E2E_GITHUB_TOKEN" `
77+
-Value $issuesToken `
78+
-DefinitionIds $triggerDefinitionIds
79+
}
80+
81+
Remove-Variable issuesToken
82+
83+
Write-Host ""
84+
Write-Host "Verifying variable names and secret flags (values are never printed)..."
85+
& cargo run --quiet -- secrets list `
86+
--org $Organization `
87+
--project $Project `
88+
--definition-ids ($allDefinitionIds -join ",")
89+
90+
if ($LASTEXITCODE -ne 0) {
91+
throw "Secret rotation succeeded, but verification failed."
92+
}
93+
}
94+
finally {
95+
Remove-Variable copilotToken -ErrorAction SilentlyContinue
96+
Remove-Variable issuesToken -ErrorAction SilentlyContinue
97+
Pop-Location
98+
}

scripts/ado-script/package-lock.json

Lines changed: 17 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

scripts/ado-script/package.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
"build:prepare-pr-base": "ncc build src/prepare-pr-base/index.ts -o .ado-build/prepare-pr-base -m -t && node -e \"const fs=require('node:fs'); fs.copyFileSync('.ado-build/prepare-pr-base/index.js','prepare-pr-base.js'); fs.rmSync('.ado-build/prepare-pr-base',{recursive:true,force:true});\"",
2727
"build:executor-e2e": "ncc build src/executor-e2e/index.ts -o .ado-build/executor-e2e -m -t && node -e \"const fs=require('node:fs'); fs.mkdirSync('test-bin',{recursive:true}); fs.copyFileSync('.ado-build/executor-e2e/index.js','test-bin/executor-e2e.js'); fs.rmSync('.ado-build/executor-e2e',{recursive:true,force:true});\"",
2828
"build:trigger-e2e": "ncc build src/trigger-e2e/index.ts -o .ado-build/trigger-e2e -m -t && node -e \"const fs=require('node:fs'); fs.mkdirSync('test-bin',{recursive:true}); fs.copyFileSync('.ado-build/trigger-e2e/index.js','test-bin/trigger-e2e.js'); fs.rmSync('.ado-build/trigger-e2e',{recursive:true,force:true});\"",
29+
"build:compiler-smoke-e2e": "ncc build src/compiler-smoke-e2e/index.ts -o .ado-build/compiler-smoke-e2e -m -t && node -e \"const fs=require('node:fs'); fs.mkdirSync('test-bin',{recursive:true}); fs.copyFileSync('.ado-build/compiler-smoke-e2e/index.js','test-bin/compiler-smoke-e2e.js'); fs.rmSync('.ado-build/compiler-smoke-e2e',{recursive:true,force:true});\"",
2930
"build:check": "ls -lh gate.js && wc -c gate.js",
3031
"codegen": "node -e \"require('node:fs').mkdirSync('schema', { recursive: true })\" && cargo run --quiet --manifest-path ../../Cargo.toml -- export-gate-schema --output schema/gate-spec.schema.json && npx json2ts schema/gate-spec.schema.json -o src/shared/types.gen.ts --bannerComment \"// AUTO-GENERATED from Rust IR via cargo run -- export-gate-schema. Do not edit; run npm run codegen.\" && cargo run --quiet --manifest-path ../../Cargo.toml -- export-fact-catalog --output src/trigger-e2e/fact-catalog.gen.json",
3132
"test": "vitest run",
@@ -35,7 +36,8 @@
3536
},
3637
"dependencies": {
3738
"azure-devops-node-api": "^14.1.0",
38-
"picomatch": "^4.0.4"
39+
"picomatch": "^4.0.4",
40+
"yaml": "^2.9.0"
3941
},
4042
"devDependencies": {
4143
"@types/node": "^20.19.39",

0 commit comments

Comments
 (0)