Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 29 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,8 @@ Current release boundary:
- this repo now targets AzureFox `1.3.0` as the current parity boundary
- deterministic lab-backed proof now includes `snapshots-disks`, `vmss`, and one Automation account
- `lighthouse` and `cross-tenant` are validated as evidence-led tenant surfaces rather than fixed row-count proof
- `devops` is validated conditionally: without `AZUREFOX_DEVOPS_ORG`, the validator expects the truthful missing-organization issue instead of pretending pipeline coverage exists
- `devops` now has three lab-owned YAML canaries once a real Azure DevOps org/project/repo context is provided:
root YAML, same-repo template follow, and named-target App Service join
- grouped `chains` follow-up remains optional here; Firefox/AzureFox `1.3.0` added more live-proof-aware `credential-path` wording, but this lab still treats grouped chain output as secondary to the standalone validation gate

## Lab Shape
Expand Down Expand Up @@ -338,6 +339,33 @@ For richer `devops` proof, point AzureFox at a real Azure DevOps organization be
export AZUREFOX_DEVOPS_ORG=<org-name>
```

Before the DevOps canaries can be synced, the Azure DevOps side needs these prerequisites:

1. A project. The default expected project name is `Azurefox Proof Lab`.
2. An Azure Repos repo. The default expected repo name is `lab-proof`.
3. A variable group. The default expected name is `af-proof-lab-vars`.
The current canaries only need the group to exist; one placeholder variable such as
`LAB_PROOF_SECRET=not-real` is enough.
4. An Azure Resource Manager service connection. The default expected name is `af-rg-reader`.
Point it at the same subscription as the lab. Workload identity federation is the preferred
scheme because AzureFox surfaces that trust path cleanly in live output.

Once those prerequisites exist, sync the tracked canary YAML into the DevOps repo and ensure the
pipeline definitions exist:

```bash
python3 scripts/sync_devops_canaries.py --org "https://dev.azure.com/<org-name>/"
```

That sync step maintains three proof pipelines in the DevOps project:

- `lab-proof`: direct root-YAML canary
- `lab-proof-template`: same-repo template-follow canary
- `lab-proof-targeted`: named-target App Service canary

If you use different DevOps names, the sync helper accepts overrides for the project, repo, service
connection, variable group, and pipeline names.

Optional flags:

```bash
Expand Down
43 changes: 43 additions & 0 deletions devops-canaries/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
## DevOps Canary Files

This directory holds the Azure DevOps YAML canary files for the proof lab.

They are here to make the lab intent obvious, not to claim that this repo
fully provisions every Azure DevOps prerequisite by itself.

Current boundary:

- the stranger still needs a real Azure DevOps org/project/repo context
- the stranger still needs working Azure DevOps auth
- this lab owns the tracked YAML canary layer and the repo/pipeline sync seam
where the Azure DevOps API allows it

The default proof setup is:

- project: `Azurefox Proof Lab`
- repo: `lab-proof`
- variable group: `af-proof-lab-vars`
- Azure Resource Manager service connection: `af-rg-reader`

The current canaries only need the variable group to exist; one placeholder
variable such as `LAB_PROOF_SECRET=not-real` is enough.

Use the sync helper after those prerequisites exist:

```bash
python3 scripts/sync_devops_canaries.py --org "https://dev.azure.com/<org-name>/"
```

The canaries are intentionally small and each one proves a specific AzureFox
behavior:

- `/azure-pipelines.yml`
- direct root-YAML evidence canary
- service connection and variable group are visible directly in the root file
- `/pipelines/template-follow.yml`
- same-repo template-follow canary
- the root file delegates into a local template
- `/templates/deploy-canary.yml`
- local template that holds the Azure-facing evidence
- `/pipelines/named-target.yml`
- explicit named-target canary for stronger `chains deployment-path` joins
18 changes: 18 additions & 0 deletions devops-canaries/azure-pipelines.yml.tmpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
trigger: none
pr: none

variables:
- group: __VARIABLE_GROUP__

pool:
vmImage: ubuntu-latest

steps:
- task: AzureCLI@2
displayName: "Read proof resource group"
inputs:
azureSubscription: __SERVICE_CONNECTION__
scriptType: bash
scriptLocation: inlineScript
inlineScript: |
az group show --name __OPS_RESOURCE_GROUP__ --query name -o tsv || true
13 changes: 13 additions & 0 deletions devops-canaries/pipelines/named-target.yml.tmpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
trigger: none
pr: none

pool:
vmImage: ubuntu-latest

steps:
- task: AzureWebApp@1
displayName: "Named target canary"
inputs:
azureSubscription: __SERVICE_CONNECTION__
appName: __NAMED_WEBAPP__
package: $(Build.SourcesDirectory)/README.md
8 changes: 8 additions & 0 deletions devops-canaries/pipelines/template-follow.yml.tmpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
trigger: none
pr: none

stages:
- stage: TemplateFollow
displayName: "Template follow canary"
jobs:
- template: /templates/deploy-canary.yml
16 changes: 16 additions & 0 deletions devops-canaries/templates/deploy-canary.yml.tmpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
jobs:
- job: TemplateFollow
displayName: "Template follow canary"
variables:
- group: __VARIABLE_GROUP__
pool:
vmImage: ubuntu-latest
steps:
- task: AzureCLI@2
displayName: "Read template-follow resource group"
inputs:
azureSubscription: __SERVICE_CONNECTION__
scriptType: bash
scriptLocation: inlineScript
inlineScript: |
az group show --name __WORKLOAD_RESOURCE_GROUP__ --query name -o tsv || true
22 changes: 21 additions & 1 deletion outputs.tf
Original file line number Diff line number Diff line change
Expand Up @@ -582,6 +582,26 @@ output "validation_manifest" {
}
devops = {
expect_unconfigured_issue_without_org = true
expected_service_connection_name = "af-rg-reader"
expected_variable_group_name = "af-proof-lab-vars"
pipelines = {
root_yaml = {
name = "lab-proof"
expect_variable_group = true
expect_named_target = false
}
template_follow = {
name = "lab-proof-template"
expect_variable_group = true
expect_named_target = false
}
named_target = {
name = "lab-proof-targeted"
expect_variable_group = false
expect_named_target = true
expected_target_clue = "App Service: ${azurerm_linux_web_app.phase2_public.name}"
}
}
}
lighthouse = {
validation_mode = "evidence-led"
Expand All @@ -602,7 +622,7 @@ output "validation_manifest" {
known_gaps = [
"cross-tenant remains tenant- and permission-dependent, so the lab keeps it evidence-led rather than row-count gated.",
"lighthouse remains subscription- and tenant-shaped; promote stronger assertions only if the lab intentionally adds delegated-management proof.",
"devops needs a real Azure DevOps organization, project, and pipeline path before it can move past conditional validation of command behavior and truthful issue surfacing.",
"devops still depends on a real Azure DevOps org/project/repo plus a visible Azure service connection and variable group; this repo owns the YAML canary sync once those prerequisites exist.",
"automation currently validates the visible zero-object execution posture, but the current AzureFox read path did not return a managed-identity type for the lab-owned Automation account during the April 8, 2026 live pass.",
]
}
Expand Down
Loading