Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
67 commits
Select commit Hold shift + click to select a range
4424cb1
docs: add PQF product catalog migration design spec
srbouffard Jul 20, 2026
cecfdae
docs: add product catalog discovery implementation plan
srbouffard Jul 20, 2026
57bff34
feat: add docs and pqf normalization for catalog discovery
srbouffard Jul 20, 2026
a71260a
fix: preserve documentation_url in docs normalization and retain stru…
srbouffard Jul 20, 2026
c43f035
feat: add product inventory diff and id mismatch report
srbouffard Jul 20, 2026
00658b0
task2: fix reviewer findings — remove unused import, format imports, …
srbouffard Jul 20, 2026
b891c7a
feat: add root-vs-leaf classifier with override support
srbouffard Jul 20, 2026
0a360fc
catalog_discovery: validate override outputs; normalize to 'root'/'le…
srbouffard Jul 20, 2026
51efa17
fix(task3): keep only squad ownership in normalize_pqf_product; canon…
srbouffard Jul 20, 2026
7fa5f73
catalog discovery: deterministic override lookup precedence; support …
srbouffard Jul 20, 2026
96ee342
docs: update task-3 report with reviewer-fix summary and tests\n\nCo-…
srbouffard Jul 20, 2026
c62f5f0
feat: add field mapping and schema-ui gap reporting
srbouffard Jul 20, 2026
a12e5c8
Task 4: Fix gap and field-mapping reports; treat UI 'squad' as owners…
srbouffard Jul 20, 2026
a088f3a
style: fix lint findings (sort imports, wrap long comment)\n\nFixes r…
srbouffard Jul 20, 2026
004ccbb
catalog_discovery: preserve intended UI field targets and respect exp…
srbouffard Jul 20, 2026
d15b44d
docs: update task-4-report with follow-up fixes summary (Task 4)\n\nC…
srbouffard Jul 20, 2026
08c52c0
feat: add pqf catalog discovery CLI and artifact generation
srbouffard Jul 20, 2026
8e69fa8
fix(catalog-discovery): fail fast when docs dir missing; exclude non-…
srbouffard Jul 20, 2026
65065ee
fix: regenerate discovery artifact from full docs source
srbouffard Jul 20, 2026
510d380
tools: load PQF schema and UI types for catalog discovery; preserve e…
srbouffard Jul 20, 2026
38ddd1a
fix: remove generated catalog artifact from computed
srbouffard Jul 20, 2026
b1d07b2
fix(catalog-discovery): pass schema/ui paths and fail fast on parse e…
srbouffard Jul 20, 2026
a167afe
fix: regenerate catalog discovery artifact from full docs set
srbouffard Jul 20, 2026
c88dfc5
fix: harden catalog discovery input and field mapping
srbouffard Jul 20, 2026
b3824ad
fix: report catalog discovery errors to stderr
srbouffard Jul 20, 2026
c3137e6
fix: finalize review hygiene and CLI coverage
srbouffard Jul 20, 2026
0663152
fix: tighten schema gaps and strict loader behavior
srbouffard Jul 20, 2026
c92c35e
feat: import full platform engineering product catalog
srbouffard Jul 20, 2026
a4f3b3d
ci: skip artifact commit job outside main
srbouffard Jul 20, 2026
d9089d1
fix: add subpaths for all mono-repo product components
srbouffard Jul 21, 2026
036a013
fix: move nginx-ingress-integrator to context_refs; show repo link in…
srbouffard Jul 21, 2026
114d203
fix: restore nginx-ingress-integrator to composed_of in discourse and…
srbouffard Jul 21, 2026
c6a9466
fix: clean up leaf product IDs — remove parent prefix, deduplicate sh…
srbouffard Jul 21, 2026
2bb5e75
fix: resolve ref: entries in scorers by loading full products directory
srbouffard Jul 21, 2026
8dddc15
fix: correct ref entries to point to root product IDs
srbouffard Jul 21, 2026
3feba3c
fix: wrap long help text in scorer argument parsers
srbouffard Jul 21, 2026
660bf7c
fix: restore matrix product to include all snap components in compose…
srbouffard Jul 21, 2026
c43e3a4
fix: convert saml-integrator from root to charm product, use ref in m…
srbouffard Jul 21, 2026
a4b3894
fix: apply ruff format to scorer files
srbouffard Jul 21, 2026
9b6f738
chore: add make ci-check target that mirrors what CI runs
srbouffard Jul 21, 2026
0ef54ea
fix: correct subproduct vs context_ref classification across 4 products
srbouffard Jul 21, 2026
eeefd9e
fix: restrict compute-metrics to main branch only
srbouffard Jul 21, 2026
ea9fa0a
fix: cancel in-progress compute-metrics on new push, restore PR branc…
srbouffard Jul 21, 2026
46ae3b0
feat: split context_refs into 'Also scored' vs 'External dependencies'
srbouffard Jul 21, 2026
03ce57d
feat: redesign Dependencies panel with tier hierarchy and medal badges
srbouffard Jul 21, 2026
b2b6265
refactor: inline sub-products inherit target_medal from parent root
srbouffard Jul 21, 2026
784dfab
fix: commit-artifacts runs on all branches, not just main
srbouffard Jul 21, 2026
f7ffe25
fix: deploy-pages fetches artifacts from compute-metrics workflow for…
srbouffard Jul 21, 2026
934b21a
fix: simplify deploy-pages to generate fresh portfolio on all branches
srbouffard Jul 21, 2026
ff2e9a4
fix: commit computed artifacts to all branches with [skip ci] flag
srbouffard Jul 21, 2026
1f5d268
fix: add pull_request trigger to compute-metrics workflow
srbouffard Jul 21, 2026
2367aa8
fix: trigger PR preview after compute-metrics completes with fresh ar…
srbouffard Jul 21, 2026
dab0f33
feat: add workflow_dispatch to preview workflow for manual triggering
srbouffard Jul 21, 2026
e814432
fix: handle preview deployment on forks gracefully
srbouffard Jul 21, 2026
be0537e
fix: add contents:write permission for PR preview deployment
srbouffard Jul 21, 2026
594877b
fix: restore allure_report_url and target_medal stripped by catalog i…
srbouffard Jul 21, 2026
211b5e5
fix: mark commit-artifacts as continue-on-error for branches with sig…
srbouffard Jul 21, 2026
dbfb6ab
fix: wire compute-metrics to auto-trigger preview with correct PR number
srbouffard Jul 21, 2026
1c82ffa
fix: use workflow_dispatch (not repository_dispatch) to trigger preview
srbouffard Jul 21, 2026
87e758b
fix: build PR preview directly in compute-metrics instead of cross-di…
srbouffard Jul 21, 2026
904b049
fix: skip rescoring unchanged products on PRs to avoid API rate limits
srbouffard Jul 21, 2026
a42e012
fix: fall back to unauthenticated public repo docs checks on PRs
srbouffard Jul 21, 2026
2c19155
fix: harden dependency row sizing across browsers
srbouffard Jul 21, 2026
3f9d14c
docs: add table column spacing refinement design spec
srbouffard Jul 21, 2026
8cf36a1
docs: add table column spacing implementation plan
srbouffard Jul 21, 2026
e52d74d
fix: rebalance dependency row column widths
srbouffard Jul 21, 2026
e64d69b
fix: rebalance products table column widths
srbouffard Jul 21, 2026
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
104 changes: 102 additions & 2 deletions .github/workflows/compute-metrics.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,19 @@ on:
- 'config/**' # re-run when dimension config changes
- 'scorers/**' # re-run when scorer logic changes
- 'engine/**' # re-run when assembly logic changes
pull_request:
paths:
- 'products/**'
- 'config/**'
- 'scorers/**'
- 'engine/**'

# Cancel any in-progress run on the same branch when a new push arrives.
# This prevents N sequential LLM runs when multiple commits land quickly.
# The nightly schedule run is never cancelled (unique group per run_id).
concurrency:
group: compute-metrics-${{ github.ref }}-${{ github.event_name == 'schedule' && github.run_id || 'push' }}
cancel-in-progress: ${{ github.event_name != 'schedule' }}

permissions:
contents: write # needed for the commit-artifacts job
Expand Down Expand Up @@ -39,62 +52,104 @@ jobs:
strategy:
matrix: ${{ fromJson(needs.discover-products.outputs.matrix) }}
fail-fast: false
max-parallel: 10 # Limit concurrent jobs to avoid GitHub API rate limits (1000 req/hr)
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0 # Needed to compare against base branch

# For pull_request: skip rescoring unchanged products, reuse committed computed file
- name: Check if product needs rescoring
id: needs_rescore
if: github.event_name == 'pull_request'
run: |
if git diff --name-only origin/${{ github.base_ref }}...HEAD -- \
products/${{ matrix.product }}.yaml config/ scorers/ engine/ \
| grep -q .; then
echo "changed=true" >> $GITHUB_OUTPUT
elif [ -f "computed/${{ matrix.product }}.json" ]; then
echo "changed=false" >> $GITHUB_OUTPUT
else
# New product with no existing computed file
echo "changed=true" >> $GITHUB_OUTPUT
fi

# If product is unchanged on PR, reuse the committed computed file
- name: Reuse existing computed file (unchanged product)
if: github.event_name == 'pull_request' && steps.needs_rescore.outputs.changed == 'false'
uses: actions/upload-artifact@v4
with:
name: computed-${{ matrix.product }}
path: computed/${{ matrix.product }}.json
retention-days: 1

- uses: actions/setup-python@v5
if: github.event_name != 'pull_request' || steps.needs_rescore.outputs.changed == 'true'
with:
python-version: '3.11'
cache: pip

- name: Install dependencies
if: github.event_name != 'pull_request' || steps.needs_rescore.outputs.changed == 'true'
run: pip install -e ".[dev]"

- name: Create scorer output directory
if: github.event_name != 'pull_request' || steps.needs_rescore.outputs.changed == 'true'
run: mkdir -p /tmp/scorers/${{ matrix.product }}

- name: Run test_verification scorer
if: github.event_name != 'pull_request' || steps.needs_rescore.outputs.changed == 'true'
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
python scorers/test_verification/scorer.py \
--product-yaml products/${{ matrix.product }}.yaml \
--products-dir products/ \
> /tmp/scorers/${{ matrix.product }}/test_verification.json

- name: Run documentation scorer
if: github.event_name != 'pull_request' || steps.needs_rescore.outputs.changed == 'true'
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
OPENROUTER_API_KEY: ${{ secrets.OPENROUTER_API_KEY }}
run: |
python scorers/documentation/scorer.py \
--product-yaml products/${{ matrix.product }}.yaml \
--products-dir products/ \
> /tmp/scorers/${{ matrix.product }}/documentation.json

- name: Run substrate_compat scorer
if: github.event_name != 'pull_request' || steps.needs_rescore.outputs.changed == 'true'
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
python scorers/substrate_compat/scorer.py \
--product-yaml products/${{ matrix.product }}.yaml \
--products-dir products/ \
> /tmp/scorers/${{ matrix.product }}/substrate_compat.json

- name: Run security_ssdlc scorer
if: github.event_name != 'pull_request' || steps.needs_rescore.outputs.changed == 'true'
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
python scorers/security_ssdlc/scorer.py \
--product-yaml products/${{ matrix.product }}.yaml \
--products-dir products/ \
> /tmp/scorers/${{ matrix.product }}/security_ssdlc.json

- name: Run support_engagement scorer
if: github.event_name != 'pull_request' || steps.needs_rescore.outputs.changed == 'true'
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
python scorers/support_engagement/scorer.py \
--product-yaml products/${{ matrix.product }}.yaml \
--products-dir products/ \
> /tmp/scorers/${{ matrix.product }}/support_engagement.json

- name: Merge scorer outputs into computed/${{ matrix.product }}.json
if: github.event_name != 'pull_request' || steps.needs_rescore.outputs.changed == 'true'
run: |
python engine/merge_computed.py \
--product-id ${{ matrix.product }} \
Expand All @@ -103,6 +158,7 @@ jobs:
--output computed/${{ matrix.product }}.json

- name: Upload computed artifact
if: github.event_name != 'pull_request' || steps.needs_rescore.outputs.changed == 'true'
uses: actions/upload-artifact@v4
with:
name: computed-${{ matrix.product }}
Expand Down Expand Up @@ -157,14 +213,58 @@ jobs:
drift-history.json
retention-days: 1

# ── 4. Commit artifacts back to main ────────────────────────────────────────
# ── 4. Build and deploy PR preview ─────────────────────────────────────────
build-preview:
needs: run-engine
if: github.event_name == 'pull_request' && github.repository == 'canonical/pqf'
runs-on: ubuntu-latest
permissions:
contents: write
pull-requests: write
steps:
- uses: actions/checkout@v4
with:
ref: ${{ github.head_ref }}

- name: Download engine artifacts (fresh medals)
uses: actions/download-artifact@v4
with:
name: engine-artifacts

- uses: actions/setup-node@v4
with:
node-version: '22'
cache: npm
cache-dependency-path: ui/package-lock.json

- name: Install UI dependencies
run: npm install
working-directory: ui

- name: Build UI
run: npm run build
working-directory: ui
# Vite copies ../public/ (containing fresh portfolio.json from artifacts) into dist/

- name: Deploy PR preview
uses: rossjrw/pr-preview-action@v1
with:
source-dir: ./ui/dist
preview-branch: gh-pages
umbrella-dir: pr-preview
action: deploy
pr-number: ${{ github.event.pull_request.number }}

# ── 5. Commit artifacts back to main ────────────────────────────────────────
commit-artifacts:
needs: run-engine
if: github.event_name == 'push'
runs-on: ubuntu-latest
continue-on-error: true # Don't fail the workflow if branch protection rejects unsigned commits
steps:
- uses: actions/checkout@v4
with:
ref: main
ref: ${{ github.ref }}
token: ${{ secrets.GITHUB_TOKEN }}

- name: Download engine artifacts
Expand Down
19 changes: 1 addition & 18 deletions .github/workflows/deploy-pages.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ name: Deploy to GitHub Pages
on:
push:
branches: [main]
workflow_dispatch:

permissions:
contents: write
Expand All @@ -18,22 +17,6 @@ jobs:
steps:
- uses: actions/checkout@v4

- uses: actions/setup-python@v5
with:
python-version: '3.11'

- name: Install Python dependencies
run: make install

- name: Assemble portfolio for production
run: >
python engine/assemble.py
--products-dir products/
--computed-dir computed/
--dimensions config/dimensions.yaml
--drift-history drift-history.json
--output public/portfolio.json

- uses: actions/setup-node@v4
with:
node-version: '22'
Expand All @@ -49,7 +32,7 @@ jobs:
working-directory: ui
# Vite copies ../public/ into dist/ automatically via publicDir config

- name: Deploy to gh-pages branch
- name: Deploy to GitHub Pages
uses: peaceiris/actions-gh-pages@v4
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
Expand Down
63 changes: 30 additions & 33 deletions .github/workflows/preview.yml
Original file line number Diff line number Diff line change
@@ -1,42 +1,43 @@
name: PR Preview

on:
pull_request:
types: [opened, synchronize, reopened, closed]
workflow_dispatch:
inputs:
run_id:
description: 'compute-metrics run ID to fetch artifacts from'
required: true
type: string
pr_number:
description: 'Pull request number to deploy preview for'
required: true
type: string

permissions:
contents: write
pull-requests: write

# Shared group with deploy-pages.yml — serializes gh-pages writes to prevent push conflicts.
concurrency:
group: gh-pages
group: gh-pages-preview-${{ inputs.pr_number }}
cancel-in-progress: false

jobs:
deploy-preview:
name: Build and deploy PR preview
runs-on: ubuntu-latest
# Only deploy previews for same-repo PRs. Fork PRs run CI but skip preview deploy.
if: github.event.action != 'closed' && github.event.pull_request.head.repo.full_name == github.repository
env:
RUN_ID: ${{ inputs.run_id }}
PR_NUMBER: ${{ inputs.pr_number }}
steps:
- uses: actions/checkout@v4

- uses: actions/setup-python@v5
with:
python-version: '3.11'

- name: Install Python dependencies
run: make install
ref: ${{ github.ref_name }}

- name: Assemble portfolio for preview
run: >
python engine/assemble.py
--products-dir products/
--computed-dir computed/
--dimensions config/dimensions.yaml
--drift-history drift-history.json
--output public/portfolio.json
- name: Download compute-metrics artifacts (fresh medals)
uses: actions/download-artifact@v4
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
run-id: ${{ env.RUN_ID }}
name: engine-artifacts

- uses: actions/setup-node@v4
with:
Expand All @@ -51,25 +52,21 @@ jobs:
- name: Build UI
run: npm run build
working-directory: ui
# Vite copies ../public/ (containing fresh portfolio.json from artifacts) into dist/

- name: Deploy PR preview
if: github.repository == 'canonical/pqf'
uses: rossjrw/pr-preview-action@v1
with:
source-dir: ./ui/dist
preview-branch: gh-pages
umbrella-dir: pr-preview
action: deploy
pr-number: ${{ env.PR_NUMBER }}

cleanup-preview:
name: Clean up PR preview
runs-on: ubuntu-latest
if: github.event.action == 'closed' && github.event.pull_request.head.repo.full_name == github.repository
steps:
- uses: actions/checkout@v4

- name: Remove PR preview
uses: rossjrw/pr-preview-action@v1
with:
preview-branch: gh-pages
umbrella-dir: pr-preview
action: remove
- name: Note about fork deployments
if: github.repository != 'canonical/pqf'
run: |
echo "✓ Build successful!"
echo "Note: PR preview deployment only works on the canonical/pqf repository."
echo "Preview URL would be: https://canonical.github.io/pqf/pr-preview/pr-${{ env.PR_NUMBER }}/"
1 change: 1 addition & 0 deletions .local/state/gh/device-id
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
fcf31720-8fef-4652-a24f-f7ffdbbc4d46
Loading
Loading