Add provenance scanner for diagnostics links - #293
Open
tomvothecoder wants to merge 26 commits into
Open
Conversation
tomvothecoder
marked this pull request as ready for review
August 14, 2026 00:57
tomvothecoder
force-pushed
the
diags/240-prov-scan
branch
from
August 18, 2026 19:45
5ca5012 to
c5be2e6
Compare
Open
7 tasks
Contributor
There was a problem hiding this comment.
Pull request overview
Adds diagnostics provenance scanning, API-backed state persistence, deployment helpers, tests, and operational documentation.
Changes:
- Adds archive discovery, validation, retry, and linking workflows.
- Adds transactional provenance-state storage and scanner APIs.
- Adds site wrappers, tests, migrations, and documentation.
Reviewed changes
Copilot reviewed 20 out of 20 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
mkdocs.yml |
Adds diagnostics documentation navigation. |
docs/user/diagnostics.md |
Documents user publishing workflow. |
docs/README.md |
Links the user guide. |
docs/github-issues/174-zppy-links/plan.md |
Updates the implementation plan. |
docs/github-issues/174-zppy-links/phase-4-provenance-scanner.md |
Expands scanner design details. |
docs/developer/README.md |
Links architecture documentation. |
docs/architecture/metadata-ingestion.md |
Cross-references diagnostics linkage. |
docs/architecture/diagnostics-linkage.md |
Documents scanner architecture and state flow. |
backend/tests/features/ingestion/test_diagnostics_link_scanner.py |
Tests scanner behavior. |
backend/tests/features/catalog/test_diagnostic_provenance_state.py |
Tests scanner APIs and persistence. |
backend/migrations/versions/20260811_000000_add_diagnostic_provenance_state.py |
Creates provenance-state storage. |
backend/app/scripts/README.md |
Documents scanner operation. |
backend/app/scripts/ingestion/sites/nersc.crontab.example |
Adds scheduled scanner examples. |
backend/app/scripts/ingestion/sites/nersc-diagnostics-scanner.sh |
Adds the NERSC wrapper. |
backend/app/scripts/ingestion/sites/lcrc-diagnostics-scanner.sh |
Adds the LCRC wrapper. |
backend/app/scripts/ingestion/diagnostics_link_scanner.py |
Implements provenance scanning and submission. |
backend/app/scripts/ingestion/diagnostics_archives.py |
Defines supported archive locations. |
backend/app/features/catalog/schemas.py |
Adds scanner request/state schemas. |
backend/app/features/catalog/models.py |
Adds the provenance-state model. |
backend/app/features/catalog/api.py |
Adds scanner state and linking endpoints. |
Suppressed comments (4)
backend/app/scripts/ingestion/diagnostics_link_scanner.py:378
- The valid archive layouts are
<tier>/<case>and<tier>/<case_group>/<case>, but this rejects the ungrouped two-part form and accepts an unsupported four-part form. As a result, normal ungrouped zppy publications are never discovered, while over-nested directories can be linked. The group calculation must use the middle component only for the three-part layout.
if len(parts) not in {3, 4} or parts[0] not in {"production", "development"}:
backend/app/scripts/ingestion/diagnostics_link_scanner.py:398
- A filename can match the regex but contain an invalid timestamp (for example, month 13).
strptime()then raisesValueErroroutside the per-candidate exception handler and aborts the entire scan, contrary to the requirement to skip malformed provenance. Treat an invalid parsed timestamp as a non-candidate.
return datetime.strptime(match.group(1), "%Y%m%d_%H%M%S_%f").replace(
tzinfo=timezone.utc
)
backend/app/scripts/ingestion/diagnostics_link_scanner.py:264
- This boundary check uses the raw URL path, so dot segments bypass it:
/archive/../outsidestarts with/archive/but resolves to/outside. Percent-encoded dot or slash variants can have the same effect depending on the server. Normalize and validate the decoded path before accepting the diagnostics URL so links cannot escape the configured archive.
if (url.scheme, url.netloc) != (
base.scheme,
base.netloc,
) or not url.path.startswith(base.path.rstrip("/") + "/"):
docs/user/diagnostics.md:26
- This says the scanner runs every 15 minutes, but the included scheduler example runs it hourly (
nersc.crontab.example:29). Users will wait for a cadence the deployment does not provide. Avoid hardcoding the cadence here or align it with the deployed schedule.
4. Wait for the scheduled SimBoard scanner to attempt linkage. Linking is not immediate; the scanner runs periodically every 15 minutes.
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Comment on lines
+257
to
+259
| settings_bytes = _read_settings_bytes(settings) | ||
| values = _parse_settings_bytes(settings_bytes) | ||
| url = urlparse(values["diagnostics_url"]) |
| 4. For each unlinked or changed candidate, it calls `POST /api/v1/diagnostics/scanner/link` with one diagnostic link and provenance metadata. The API resolves the target SimBoard Case from case name, machine, and HPC username, then atomically upserts the case diagnostic link and scanner state. A successful request returns no content. | ||
| 5. On a later run, the persisted state makes a matching candidate unchanged. A changed filename or fingerprint is submitted again and updates the state for that machine/path identity. | ||
|
|
||
| Scanner API access requires the diagnostics-scanner role. A state lookup can return no state, and it returns an error when the supplied machine is unknown. The scanner-link endpoint requires exactly one diagnostic and rejects unsafe archive-relative paths; case-resolution failures also prevent a successful state update. |
| 20 * * * * cd ${REPO_DIR} && ${REPO_DIR}/backend/app/scripts/ingestion/sites/nersc-diagnostics-scanner.sh >> ${REPO_DIR}/backend/app/scripts/ingestion/sites/nersc-diagnostics-scanner.log 2>&1 | ||
|
|
||
| # Chrysalis diagnostics provenance scan; use its local checkout path for REPO_DIR. | ||
| 25 * * * * cd ${REPO_DIR} && ${REPO_DIR}/backend/app/scripts/ingestion/sites/lcrc-diagnostics-scanner.sh >> ${REPO_DIR}/backend/app/scripts/ingestion/sites/lcrc-diagnostics-scanner.log 2>&1 |
|
|
||
| ## Publish and find the link | ||
|
|
||
| 1. Run and publish the zppy diagnostics using the configured `simulation_type`. This generates the `provenance.settings` file used for SimBoard publication. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
Closes #240.
Adds a diagnostics provenance scanner that discovers diagnostic archives, validates scanner inputs, and idempotently links case diagnostics through the API. Persists successful scanner provenance state so scans can be resumed safely, with deployment helpers and operational documentation for supported sites.
Also adds regression coverage for scanner-state lookup, authorization, validation, missing-machine handling, idempotent links, rollback behavior, and scanner ingestion behavior.
Validation
make backend-test(1003 passed; 100% coverage)Deployment Notes
Apply the included Alembic migration before enabling scheduled scanner jobs. Configure site credentials and scheduler entries as documented.