fhir-scorecard 0.3.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- fhir_scorecard-0.3.0/.gitattributes +30 -0
- fhir_scorecard-0.3.0/.github/CODEOWNERS +2 -0
- fhir_scorecard-0.3.0/.github/ISSUE_TEMPLATE/add-endpoint.yml +74 -0
- fhir_scorecard-0.3.0/.github/ISSUE_TEMPLATE/bug_report.yml +53 -0
- fhir_scorecard-0.3.0/.github/ISSUE_TEMPLATE/config.yml +8 -0
- fhir_scorecard-0.3.0/.github/ISSUE_TEMPLATE/feature_request.yml +35 -0
- fhir_scorecard-0.3.0/.github/ISSUE_TEMPLATE/remove-or-dispute.yml +34 -0
- fhir_scorecard-0.3.0/.github/allowed_signers +1 -0
- fhir_scorecard-0.3.0/.github/dependabot.yml +42 -0
- fhir_scorecard-0.3.0/.github/workflows/compliance-bundle.yml +182 -0
- fhir_scorecard-0.3.0/.github/workflows/live-integrity.yml +85 -0
- fhir_scorecard-0.3.0/.github/workflows/pages.yml +235 -0
- fhir_scorecard-0.3.0/.github/workflows/pypi-publish.yml +286 -0
- fhir_scorecard-0.3.0/.github/workflows/recheck.yml +81 -0
- fhir_scorecard-0.3.0/.github/workflows/release.yml +236 -0
- fhir_scorecard-0.3.0/.github/workflows/scorecard.yml +65 -0
- fhir_scorecard-0.3.0/.github/workflows/security.yml +106 -0
- fhir_scorecard-0.3.0/.github/workflows/verify.yml +43 -0
- fhir_scorecard-0.3.0/.gitignore +22 -0
- fhir_scorecard-0.3.0/.pre-commit-config.yaml +50 -0
- fhir_scorecard-0.3.0/.python-version +1 -0
- fhir_scorecard-0.3.0/CHANGELOG.md +1486 -0
- fhir_scorecard-0.3.0/CITATION.cff +25 -0
- fhir_scorecard-0.3.0/CODE_OF_CONDUCT.md +26 -0
- fhir_scorecard-0.3.0/CONTRIBUTING.md +124 -0
- fhir_scorecard-0.3.0/LICENSE +202 -0
- fhir_scorecard-0.3.0/Makefile +65 -0
- fhir_scorecard-0.3.0/PKG-INFO +678 -0
- fhir_scorecard-0.3.0/README.md +655 -0
- fhir_scorecard-0.3.0/ROADMAP.md +464 -0
- fhir_scorecard-0.3.0/SECURITY.md +50 -0
- fhir_scorecard-0.3.0/action/render_result.py +174 -0
- fhir_scorecard-0.3.0/action.yml +106 -0
- fhir_scorecard-0.3.0/corpus/SOURCES.json +40 -0
- fhir_scorecard-0.3.0/corpus/hl7/fhir-r4-capabilitystatement.html +2241 -0
- fhir_scorecard-0.3.0/corpus/hl7/fhir-r4-http.html +1961 -0
- fhir_scorecard-0.3.0/corpus/hl7/smart-app-launch-conformance.html +588 -0
- fhir_scorecard-0.3.0/corpus/hl7/us-core-index.html +4652 -0
- fhir_scorecard-0.3.0/data/CANDIDATES.md +618 -0
- fhir_scorecard-0.3.0/data/bundle/plan.json +22 -0
- fhir_scorecard-0.3.0/data/cohorts/alabama-marketplace.json +73 -0
- fhir_scorecard-0.3.0/data/cohorts/alabama-marketplace.roster.csv +5 -0
- fhir_scorecard-0.3.0/data/cohorts/alaska-marketplace.json +51 -0
- fhir_scorecard-0.3.0/data/cohorts/alaska-marketplace.roster.csv +3 -0
- fhir_scorecard-0.3.0/data/cohorts/arizona-marketplace.json +113 -0
- fhir_scorecard-0.3.0/data/cohorts/arizona-marketplace.roster.csv +8 -0
- fhir_scorecard-0.3.0/data/cohorts/california.json +376 -0
- fhir_scorecard-0.3.0/data/cohorts/delaware-marketplace.json +62 -0
- fhir_scorecard-0.3.0/data/cohorts/delaware-marketplace.roster.csv +4 -0
- fhir_scorecard-0.3.0/data/cohorts/florida-marketplace.json +234 -0
- fhir_scorecard-0.3.0/data/cohorts/florida-marketplace.roster.csv +16 -0
- fhir_scorecard-0.3.0/data/cohorts/indiana-marketplace.json +80 -0
- fhir_scorecard-0.3.0/data/cohorts/indiana-marketplace.roster.csv +6 -0
- fhir_scorecard-0.3.0/data/cohorts/iowa-marketplace.json +106 -0
- fhir_scorecard-0.3.0/data/cohorts/iowa-marketplace.roster.csv +7 -0
- fhir_scorecard-0.3.0/data/cohorts/kansas-marketplace.json +101 -0
- fhir_scorecard-0.3.0/data/cohorts/kansas-marketplace.roster.csv +7 -0
- fhir_scorecard-0.3.0/data/cohorts/louisiana-marketplace.json +95 -0
- fhir_scorecard-0.3.0/data/cohorts/louisiana-marketplace.roster.csv +7 -0
- fhir_scorecard-0.3.0/data/cohorts/michigan-marketplace.json +112 -0
- fhir_scorecard-0.3.0/data/cohorts/michigan-marketplace.roster.csv +8 -0
- fhir_scorecard-0.3.0/data/cohorts/mississippi-marketplace.json +90 -0
- fhir_scorecard-0.3.0/data/cohorts/mississippi-marketplace.roster.csv +6 -0
- fhir_scorecard-0.3.0/data/cohorts/missouri-marketplace.json +113 -0
- fhir_scorecard-0.3.0/data/cohorts/missouri-marketplace.roster.csv +8 -0
- fhir_scorecard-0.3.0/data/cohorts/nebraska-marketplace.json +89 -0
- fhir_scorecard-0.3.0/data/cohorts/nebraska-marketplace.roster.csv +6 -0
- fhir_scorecard-0.3.0/data/cohorts/north-carolina-marketplace.json +97 -0
- fhir_scorecard-0.3.0/data/cohorts/north-carolina-marketplace.roster.csv +7 -0
- fhir_scorecard-0.3.0/data/cohorts/ohio-marketplace.json +174 -0
- fhir_scorecard-0.3.0/data/cohorts/ohio-marketplace.roster.csv +12 -0
- fhir_scorecard-0.3.0/data/cohorts/oklahoma-marketplace.json +118 -0
- fhir_scorecard-0.3.0/data/cohorts/oklahoma-marketplace.roster.csv +8 -0
- fhir_scorecard-0.3.0/data/cohorts/texas-marketplace.json +249 -0
- fhir_scorecard-0.3.0/data/cohorts/texas-marketplace.roster.csv +16 -0
- fhir_scorecard-0.3.0/data/cohorts/west-virginia-marketplace.json +51 -0
- fhir_scorecard-0.3.0/data/cohorts/west-virginia-marketplace.roster.csv +3 -0
- fhir_scorecard-0.3.0/data/cohorts/wisconsin-marketplace.json +173 -0
- fhir_scorecard-0.3.0/data/cohorts/wisconsin-marketplace.roster.csv +13 -0
- fhir_scorecard-0.3.0/data/cohorts/wyoming-marketplace.json +50 -0
- fhir_scorecard-0.3.0/data/cohorts/wyoming-marketplace.roster.csv +3 -0
- fhir_scorecard-0.3.0/data/frames/qhp-landscape-py2026-individual-medical.csv +177 -0
- fhir_scorecard-0.3.0/data/history.json +500 -0
- fhir_scorecard-0.3.0/data/registry.json +1159 -0
- fhir_scorecard-0.3.0/data/rejected.json +131 -0
- fhir_scorecard-0.3.0/docs/I18N.md +26 -0
- fhir_scorecard-0.3.0/docs/PR-TRIAGE.md +503 -0
- fhir_scorecard-0.3.0/docs/RESPONSIBLE-TECH-AUDITS.md +148 -0
- fhir_scorecard-0.3.0/docs/SAMPLING-FRAME.md +197 -0
- fhir_scorecard-0.3.0/docs/adr/0000-record-architecture-decisions.md +30 -0
- fhir_scorecard-0.3.0/docs/adr/0001-release-versioning-na.md +50 -0
- fhir_scorecard-0.3.0/docs/adr/0002-release-versioning-applies-action-export.md +91 -0
- fhir_scorecard-0.3.0/docs/adr/0003-ai-narration-outside-the-graded-path.md +86 -0
- fhir_scorecard-0.3.0/docs/adr/0004-accessibility-and-weight-gates-without-a-browser.md +121 -0
- fhir_scorecard-0.3.0/docs/adr/0005-a-leaderboard-that-publishes-what-meets-the-floor.md +79 -0
- fhir_scorecard-0.3.0/docs/adr/0006-google-analytics-4.md +79 -0
- fhir_scorecard-0.3.0/docs/adr/0007-bundle-conversion-events.md +84 -0
- fhir_scorecard-0.3.0/docs/adr/0008-grade-history.md +112 -0
- fhir_scorecard-0.3.0/docs/adr/0009-readiness-report-regulatory-statements.md +57 -0
- fhir_scorecard-0.3.0/docs/ci-action.md +143 -0
- fhir_scorecard-0.3.0/docs/compliance-bundle-owner-steps.md +257 -0
- fhir_scorecard-0.3.0/docs/compliance-bundle-plan.md +188 -0
- fhir_scorecard-0.3.0/docs/findings/2026-08-15-anthem-multi-tenant-attribution.md +136 -0
- fhir_scorecard-0.3.0/docs/findings/2026-08-15-california-payer-cohort.json +173 -0
- fhir_scorecard-0.3.0/docs/findings/2026-08-15-california-payer-cohort.md +292 -0
- fhir_scorecard-0.3.0/docs/mcp-registry.md +94 -0
- fhir_scorecard-0.3.0/docs/payer-verifiability.md +138 -0
- fhir_scorecard-0.3.0/evals/ai/README.md +14 -0
- fhir_scorecard-0.3.0/evals/ai/results/2026-08-21-narration-bedrock-claude-sonnet-4-6.json +2018 -0
- fhir_scorecard-0.3.0/infra/compliance-bundle/.terraform.lock.hcl +46 -0
- fhir_scorecard-0.3.0/infra/compliance-bundle/backend.tf +14 -0
- fhir_scorecard-0.3.0/infra/compliance-bundle/common.py +527 -0
- fhir_scorecard-0.3.0/infra/compliance-bundle/main.tf +624 -0
- fhir_scorecard-0.3.0/infra/compliance-bundle/setup_handler.py +610 -0
- fhir_scorecard-0.3.0/infra/compliance-bundle/webhook_handler.py +188 -0
- fhir_scorecard-0.3.0/pyproject.toml +115 -0
- fhir_scorecard-0.3.0/scripts/build-lambda-package.sh +79 -0
- fhir_scorecard-0.3.0/scripts/stripe-setup.sh +138 -0
- fhir_scorecard-0.3.0/server.json +37 -0
- fhir_scorecard-0.3.0/src/fhir_scorecard/__init__.py +3 -0
- fhir_scorecard-0.3.0/src/fhir_scorecard/accessibility.py +341 -0
- fhir_scorecard-0.3.0/src/fhir_scorecard/ai/__init__.py +8 -0
- fhir_scorecard-0.3.0/src/fhir_scorecard/ai/corpus.py +278 -0
- fhir_scorecard-0.3.0/src/fhir_scorecard/ai/eval.py +207 -0
- fhir_scorecard-0.3.0/src/fhir_scorecard/ai/narrate.py +442 -0
- fhir_scorecard-0.3.0/src/fhir_scorecard/ai/provider.py +196 -0
- fhir_scorecard-0.3.0/src/fhir_scorecard/ai/retrieval.py +94 -0
- fhir_scorecard-0.3.0/src/fhir_scorecard/analytics.py +379 -0
- fhir_scorecard-0.3.0/src/fhir_scorecard/archive.py +589 -0
- fhir_scorecard-0.3.0/src/fhir_scorecard/assets/bundle-setup.js +157 -0
- fhir_scorecard-0.3.0/src/fhir_scorecard/assets/bundle.js +52 -0
- fhir_scorecard-0.3.0/src/fhir_scorecard/assets/favicon.svg +6 -0
- fhir_scorecard-0.3.0/src/fhir_scorecard/assets/site.css +445 -0
- fhir_scorecard-0.3.0/src/fhir_scorecard/assets/social-card.png +0 -0
- fhir_scorecard-0.3.0/src/fhir_scorecard/assets/uswds/VERSION.txt +13 -0
- fhir_scorecard-0.3.0/src/fhir_scorecard/assets/uswds/css/uswds.min.css +4 -0
- fhir_scorecard-0.3.0/src/fhir_scorecard/assets/uswds/fonts/merriweather/Latin-Merriweather-Bold.woff2 +0 -0
- fhir_scorecard-0.3.0/src/fhir_scorecard/assets/uswds/fonts/merriweather/Latin-Merriweather-BoldItalic.woff2 +0 -0
- fhir_scorecard-0.3.0/src/fhir_scorecard/assets/uswds/fonts/merriweather/Latin-Merriweather-Italic.woff2 +0 -0
- fhir_scorecard-0.3.0/src/fhir_scorecard/assets/uswds/fonts/merriweather/Latin-Merriweather-Light.woff2 +0 -0
- fhir_scorecard-0.3.0/src/fhir_scorecard/assets/uswds/fonts/merriweather/Latin-Merriweather-LightItalic.woff2 +0 -0
- fhir_scorecard-0.3.0/src/fhir_scorecard/assets/uswds/fonts/merriweather/Latin-Merriweather-Regular.woff2 +0 -0
- fhir_scorecard-0.3.0/src/fhir_scorecard/assets/uswds/fonts/roboto-mono/roboto-mono-v5-latin-300.woff2 +0 -0
- fhir_scorecard-0.3.0/src/fhir_scorecard/assets/uswds/fonts/roboto-mono/roboto-mono-v5-latin-300italic.woff2 +0 -0
- fhir_scorecard-0.3.0/src/fhir_scorecard/assets/uswds/fonts/roboto-mono/roboto-mono-v5-latin-700.woff2 +0 -0
- fhir_scorecard-0.3.0/src/fhir_scorecard/assets/uswds/fonts/roboto-mono/roboto-mono-v5-latin-700italic.woff2 +0 -0
- fhir_scorecard-0.3.0/src/fhir_scorecard/assets/uswds/fonts/roboto-mono/roboto-mono-v5-latin-italic.woff2 +0 -0
- fhir_scorecard-0.3.0/src/fhir_scorecard/assets/uswds/fonts/roboto-mono/roboto-mono-v5-latin-regular.woff2 +0 -0
- fhir_scorecard-0.3.0/src/fhir_scorecard/assets/uswds/fonts/source-sans-pro/sourcesanspro-bold-webfont.woff2 +0 -0
- fhir_scorecard-0.3.0/src/fhir_scorecard/assets/uswds/fonts/source-sans-pro/sourcesanspro-bolditalic-webfont.woff2 +0 -0
- fhir_scorecard-0.3.0/src/fhir_scorecard/assets/uswds/fonts/source-sans-pro/sourcesanspro-italic-webfont.woff2 +0 -0
- fhir_scorecard-0.3.0/src/fhir_scorecard/assets/uswds/fonts/source-sans-pro/sourcesanspro-light-webfont.woff2 +0 -0
- fhir_scorecard-0.3.0/src/fhir_scorecard/assets/uswds/fonts/source-sans-pro/sourcesanspro-lightitalic-webfont.woff2 +0 -0
- fhir_scorecard-0.3.0/src/fhir_scorecard/assets/uswds/fonts/source-sans-pro/sourcesanspro-regular-webfont.woff2 +0 -0
- fhir_scorecard-0.3.0/src/fhir_scorecard/assets/uswds/img/checkbox-indeterminate-alt.svg +1 -0
- fhir_scorecard-0.3.0/src/fhir_scorecard/assets/uswds/img/checkbox-indeterminate.svg +1 -0
- fhir_scorecard-0.3.0/src/fhir_scorecard/assets/uswds/img/correct8-alt.svg +1 -0
- fhir_scorecard-0.3.0/src/fhir_scorecard/assets/uswds/img/correct8.svg +1 -0
- fhir_scorecard-0.3.0/src/fhir_scorecard/assets/uswds/img/file-excel.svg +1 -0
- fhir_scorecard-0.3.0/src/fhir_scorecard/assets/uswds/img/file-pdf.svg +1 -0
- fhir_scorecard-0.3.0/src/fhir_scorecard/assets/uswds/img/file-video.svg +1 -0
- fhir_scorecard-0.3.0/src/fhir_scorecard/assets/uswds/img/file-word.svg +1 -0
- fhir_scorecard-0.3.0/src/fhir_scorecard/assets/uswds/img/file.svg +1 -0
- fhir_scorecard-0.3.0/src/fhir_scorecard/assets/uswds/img/hero.jpg +0 -0
- fhir_scorecard-0.3.0/src/fhir_scorecard/assets/uswds/img/loader.svg +1 -0
- fhir_scorecard-0.3.0/src/fhir_scorecard/assets/uswds/img/sprite.svg +1 -0
- fhir_scorecard-0.3.0/src/fhir_scorecard/assets/uswds/img/usa-icons/add.svg +1 -0
- fhir_scorecard-0.3.0/src/fhir_scorecard/assets/uswds/img/usa-icons/arrow_back.svg +1 -0
- fhir_scorecard-0.3.0/src/fhir_scorecard/assets/uswds/img/usa-icons/calendar_today.svg +1 -0
- fhir_scorecard-0.3.0/src/fhir_scorecard/assets/uswds/img/usa-icons/check_circle.svg +1 -0
- fhir_scorecard-0.3.0/src/fhir_scorecard/assets/uswds/img/usa-icons/close.svg +1 -0
- fhir_scorecard-0.3.0/src/fhir_scorecard/assets/uswds/img/usa-icons/error.svg +1 -0
- fhir_scorecard-0.3.0/src/fhir_scorecard/assets/uswds/img/usa-icons/expand_less.svg +1 -0
- fhir_scorecard-0.3.0/src/fhir_scorecard/assets/uswds/img/usa-icons/expand_more.svg +1 -0
- fhir_scorecard-0.3.0/src/fhir_scorecard/assets/uswds/img/usa-icons/info.svg +1 -0
- fhir_scorecard-0.3.0/src/fhir_scorecard/assets/uswds/img/usa-icons/launch.svg +1 -0
- fhir_scorecard-0.3.0/src/fhir_scorecard/assets/uswds/img/usa-icons/navigate_before.svg +1 -0
- fhir_scorecard-0.3.0/src/fhir_scorecard/assets/uswds/img/usa-icons/navigate_far_before.svg +1 -0
- fhir_scorecard-0.3.0/src/fhir_scorecard/assets/uswds/img/usa-icons/navigate_far_next.svg +1 -0
- fhir_scorecard-0.3.0/src/fhir_scorecard/assets/uswds/img/usa-icons/navigate_next.svg +1 -0
- fhir_scorecard-0.3.0/src/fhir_scorecard/assets/uswds/img/usa-icons/remove.svg +1 -0
- fhir_scorecard-0.3.0/src/fhir_scorecard/assets/uswds/img/usa-icons/search.svg +1 -0
- fhir_scorecard-0.3.0/src/fhir_scorecard/assets/uswds/img/usa-icons/unfold_more.svg +1 -0
- fhir_scorecard-0.3.0/src/fhir_scorecard/assets/uswds/img/usa-icons/warning.svg +1 -0
- fhir_scorecard-0.3.0/src/fhir_scorecard/assets/uswds/img/usa-icons-bg/check--blue-60v.svg +1 -0
- fhir_scorecard-0.3.0/src/fhir_scorecard/assets/uswds/img/usa-icons-bg/error--white.svg +1 -0
- fhir_scorecard-0.3.0/src/fhir_scorecard/assets/uswds/img/usa-icons-bg/launch--white.svg +1 -0
- fhir_scorecard-0.3.0/src/fhir_scorecard/assets/uswds/js/uswds-init.min.js +2 -0
- fhir_scorecard-0.3.0/src/fhir_scorecard/assets/uswds/js/uswds.min.js +84 -0
- fhir_scorecard-0.3.0/src/fhir_scorecard/audit.py +683 -0
- fhir_scorecard-0.3.0/src/fhir_scorecard/backend.py +284 -0
- fhir_scorecard-0.3.0/src/fhir_scorecard/bundle.py +541 -0
- fhir_scorecard-0.3.0/src/fhir_scorecard/bundle_order.py +194 -0
- fhir_scorecard-0.3.0/src/fhir_scorecard/bundle_report.py +332 -0
- fhir_scorecard-0.3.0/src/fhir_scorecard/capability.py +427 -0
- fhir_scorecard-0.3.0/src/fhir_scorecard/ci_report.py +319 -0
- fhir_scorecard-0.3.0/src/fhir_scorecard/cli.py +2083 -0
- fhir_scorecard-0.3.0/src/fhir_scorecard/cohort.py +313 -0
- fhir_scorecard-0.3.0/src/fhir_scorecard/cohort_matrix.py +263 -0
- fhir_scorecard-0.3.0/src/fhir_scorecard/concentration.py +439 -0
- fhir_scorecard-0.3.0/src/fhir_scorecard/conditions.py +160 -0
- fhir_scorecard-0.3.0/src/fhir_scorecard/coverage.py +542 -0
- fhir_scorecard-0.3.0/src/fhir_scorecard/dataset.py +371 -0
- fhir_scorecard-0.3.0/src/fhir_scorecard/deadline.py +227 -0
- fhir_scorecard-0.3.0/src/fhir_scorecard/diff.py +539 -0
- fhir_scorecard-0.3.0/src/fhir_scorecard/drift.py +662 -0
- fhir_scorecard-0.3.0/src/fhir_scorecard/entity_report.py +552 -0
- fhir_scorecard-0.3.0/src/fhir_scorecard/feeds.py +544 -0
- fhir_scorecard-0.3.0/src/fhir_scorecard/fetch.py +510 -0
- fhir_scorecard-0.3.0/src/fhir_scorecard/gate.py +61 -0
- fhir_scorecard-0.3.0/src/fhir_scorecard/grade_history.py +314 -0
- fhir_scorecard-0.3.0/src/fhir_scorecard/grading.py +845 -0
- fhir_scorecard-0.3.0/src/fhir_scorecard/intake.py +666 -0
- fhir_scorecard-0.3.0/src/fhir_scorecard/leaderboard.py +185 -0
- fhir_scorecard-0.3.0/src/fhir_scorecard/matrix.py +635 -0
- fhir_scorecard-0.3.0/src/fhir_scorecard/mcp.py +346 -0
- fhir_scorecard-0.3.0/src/fhir_scorecard/operator.py +127 -0
- fhir_scorecard-0.3.0/src/fhir_scorecard/over_time.py +412 -0
- fhir_scorecard-0.3.0/src/fhir_scorecard/published.py +735 -0
- fhir_scorecard-0.3.0/src/fhir_scorecard/py.typed +0 -0
- fhir_scorecard-0.3.0/src/fhir_scorecard/readiness.py +482 -0
- fhir_scorecard-0.3.0/src/fhir_scorecard/registry.py +207 -0
- fhir_scorecard-0.3.0/src/fhir_scorecard/report.py +48 -0
- fhir_scorecard-0.3.0/src/fhir_scorecard/reprobe.py +129 -0
- fhir_scorecard-0.3.0/src/fhir_scorecard/reverify.py +419 -0
- fhir_scorecard-0.3.0/src/fhir_scorecard/site.py +2432 -0
- fhir_scorecard-0.3.0/src/fhir_scorecard/snapshot.py +188 -0
- fhir_scorecard-0.3.0/src/fhir_scorecard/statistics.py +220 -0
- fhir_scorecard-0.3.0/src/fhir_scorecard/vantage.py +620 -0
- fhir_scorecard-0.3.0/src/fhir_scorecard/weight.py +128 -0
- fhir_scorecard-0.3.0/tests/conftest.py +80 -0
- fhir_scorecard-0.3.0/tests/fixtures/README.md +89 -0
- fhir_scorecard-0.3.0/tests/fixtures/ai/not-narratable.json +48 -0
- fhir_scorecard-0.3.0/tests/fixtures/ai/scorecards.json +1998 -0
- fhir_scorecard-0.3.0/tests/fixtures/aspirus-patient-access/refusal.json +11 -0
- fhir_scorecard-0.3.0/tests/fixtures/bcbs-arizona-patient-access/refusal.json +11 -0
- fhir_scorecard-0.3.0/tests/fixtures/cms-blue-button-2/metadata.json +253 -0
- fhir_scorecard-0.3.0/tests/fixtures/cms-blue-button-2/smart.json +36 -0
- fhir_scorecard-0.3.0/tests/fixtures/inferno-reference/metadata.json +1085 -0
- fhir_scorecard-0.3.0/tests/fixtures/inferno-reference/smart.json +513 -0
- fhir_scorecard-0.3.0/tests/fixtures/operator-registry.json +24 -0
- fhir_scorecard-0.3.0/tests/fixtures/oracle-health-open/metadata.json +1883 -0
- fhir_scorecard-0.3.0/tests/fixtures/registry.json +66 -0
- fhir_scorecard-0.3.0/tests/test_absence_cannot_raise_a_grade.py +326 -0
- fhir_scorecard-0.3.0/tests/test_accessibility_and_weight.py +423 -0
- fhir_scorecard-0.3.0/tests/test_ai_narration.py +570 -0
- fhir_scorecard-0.3.0/tests/test_alternation.py +357 -0
- fhir_scorecard-0.3.0/tests/test_analytics.py +721 -0
- fhir_scorecard-0.3.0/tests/test_app_to_server_wiring.py +218 -0
- fhir_scorecard-0.3.0/tests/test_archive.py +534 -0
- fhir_scorecard-0.3.0/tests/test_asked_and_not_served.py +411 -0
- fhir_scorecard-0.3.0/tests/test_audit_noindex.py +62 -0
- fhir_scorecard-0.3.0/tests/test_backend.py +240 -0
- fhir_scorecard-0.3.0/tests/test_bundle.py +545 -0
- fhir_scorecard-0.3.0/tests/test_bundle_order.py +251 -0
- fhir_scorecard-0.3.0/tests/test_bundle_report.py +240 -0
- fhir_scorecard-0.3.0/tests/test_bundle_scripts.py +193 -0
- fhir_scorecard-0.3.0/tests/test_capability.py +51 -0
- fhir_scorecard-0.3.0/tests/test_ci_action.py +517 -0
- fhir_scorecard-0.3.0/tests/test_ci_report.py +613 -0
- fhir_scorecard-0.3.0/tests/test_cli_and_report.py +839 -0
- fhir_scorecard-0.3.0/tests/test_cli_bundle_command.py +266 -0
- fhir_scorecard-0.3.0/tests/test_cohort.py +579 -0
- fhir_scorecard-0.3.0/tests/test_cohort_matrix.py +291 -0
- fhir_scorecard-0.3.0/tests/test_compliance_bundle_contract.py +177 -0
- fhir_scorecard-0.3.0/tests/test_compliance_bundle_infra.py +970 -0
- fhir_scorecard-0.3.0/tests/test_concentration.py +309 -0
- fhir_scorecard-0.3.0/tests/test_conditions.py +533 -0
- fhir_scorecard-0.3.0/tests/test_coverage.py +437 -0
- fhir_scorecard-0.3.0/tests/test_dataset.py +135 -0
- fhir_scorecard-0.3.0/tests/test_deadline.py +148 -0
- fhir_scorecard-0.3.0/tests/test_diff.py +584 -0
- fhir_scorecard-0.3.0/tests/test_drift.py +275 -0
- fhir_scorecard-0.3.0/tests/test_entity_report.py +707 -0
- fhir_scorecard-0.3.0/tests/test_failure_kinds.py +610 -0
- fhir_scorecard-0.3.0/tests/test_feeds.py +544 -0
- fhir_scorecard-0.3.0/tests/test_fetch_bytes.py +104 -0
- fhir_scorecard-0.3.0/tests/test_findings_evidence.py +325 -0
- fhir_scorecard-0.3.0/tests/test_grade_history.py +486 -0
- fhir_scorecard-0.3.0/tests/test_grading.py +572 -0
- fhir_scorecard-0.3.0/tests/test_headline_counts.py +399 -0
- fhir_scorecard-0.3.0/tests/test_intake.py +587 -0
- fhir_scorecard-0.3.0/tests/test_leaderboard.py +312 -0
- fhir_scorecard-0.3.0/tests/test_live_integrity_pending_publish.py +434 -0
- fhir_scorecard-0.3.0/tests/test_live_site_check.py +315 -0
- fhir_scorecard-0.3.0/tests/test_matrix.py +733 -0
- fhir_scorecard-0.3.0/tests/test_mcp.py +146 -0
- fhir_scorecard-0.3.0/tests/test_mcp_registry_manifest.py +115 -0
- fhir_scorecard-0.3.0/tests/test_not_observed.py +337 -0
- fhir_scorecard-0.3.0/tests/test_offline_mode.py +227 -0
- fhir_scorecard-0.3.0/tests/test_over_time.py +348 -0
- fhir_scorecard-0.3.0/tests/test_plan_evidence.py +391 -0
- fhir_scorecard-0.3.0/tests/test_probe_contract.py +537 -0
- fhir_scorecard-0.3.0/tests/test_profile_declarations.py +140 -0
- fhir_scorecard-0.3.0/tests/test_published_grades.py +560 -0
- fhir_scorecard-0.3.0/tests/test_published_states.py +382 -0
- fhir_scorecard-0.3.0/tests/test_readiness.py +397 -0
- fhir_scorecard-0.3.0/tests/test_registry_and_fetch.py +388 -0
- fhir_scorecard-0.3.0/tests/test_reprobe.py +153 -0
- fhir_scorecard-0.3.0/tests/test_reverify.py +468 -0
- fhir_scorecard-0.3.0/tests/test_shipped_code_is_gated.py +138 -0
- fhir_scorecard-0.3.0/tests/test_site.py +602 -0
- fhir_scorecard-0.3.0/tests/test_site_audit.py +799 -0
- fhir_scorecard-0.3.0/tests/test_site_bundle_pages.py +297 -0
- fhir_scorecard-0.3.0/tests/test_snapshot.py +240 -0
- fhir_scorecard-0.3.0/tests/test_stated_counts.py +324 -0
- fhir_scorecard-0.3.0/tests/test_statistics.py +214 -0
- fhir_scorecard-0.3.0/tests/test_status_claims.py +144 -0
- fhir_scorecard-0.3.0/tests/test_three_states_and_vantages.py +541 -0
- fhir_scorecard-0.3.0/tests/test_unreadable_capability.py +350 -0
- fhir_scorecard-0.3.0/tests/test_vantage.py +628 -0
- fhir_scorecard-0.3.0/tests/test_workflow_shell_safety.py +453 -0
- fhir_scorecard-0.3.0/tools/verify_live_site.py +945 -0
- fhir_scorecard-0.3.0/uv.lock +1456 -0
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
|
|
2
|
+
# CI is the authoritative writer of the drift/availability history: it runs daily from a
|
|
3
|
+
# stable vantage and commits what it observed. Local grade runs overwrite it, which produced a
|
|
4
|
+
# rebase conflict every time. Union-merge keeps both sides rather than failing the rebase; CI
|
|
5
|
+
# rewrites the file wholesale on its next run regardless.
|
|
6
|
+
data/history.json merge=union
|
|
7
|
+
|
|
8
|
+
# GitHub Actions downloads a source archive for every `uses:` invocation. Keep that archive to
|
|
9
|
+
# the Action runtime instead of shipping the curated registry, the cohort files, the captured
|
|
10
|
+
# fixtures, and the test suite to every consumer. The published dataset lives on the site; a
|
|
11
|
+
# consumer gating their own endpoint has no use for a copy of it.
|
|
12
|
+
/* export-ignore
|
|
13
|
+
/action -export-ignore
|
|
14
|
+
/action.yml -export-ignore
|
|
15
|
+
/CODE_OF_CONDUCT.md -export-ignore
|
|
16
|
+
/LICENSE -export-ignore
|
|
17
|
+
/pyproject.toml -export-ignore
|
|
18
|
+
/README.md -export-ignore
|
|
19
|
+
/SECURITY.md -export-ignore
|
|
20
|
+
/src -export-ignore
|
|
21
|
+
# The vendored design system (stylesheets, fonts, icons) exists to build the site. The Action
|
|
22
|
+
# runtime a consumer downloads runs `check` and never builds a site, so the 50-odd asset files
|
|
23
|
+
# stay out of the archive the same way the dataset does. A checkout has them; the archive is
|
|
24
|
+
# the Action runtime, bounded on purpose.
|
|
25
|
+
/src/fhir_scorecard/assets export-ignore
|
|
26
|
+
|
|
27
|
+
# Retained specification pages are evidence: keep their bytes exactly as fetched so the
|
|
28
|
+
# SHA-256 values in corpus/SOURCES.json stay true on every checkout. They serve the optional
|
|
29
|
+
# narration layer, not the Action runtime, so they stay out of the archive with the dataset.
|
|
30
|
+
/corpus/** -text
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
name: Add or correct an endpoint
|
|
2
|
+
description: Tell us about a public FHIR endpoint we are missing or have wrong
|
|
3
|
+
title: "[endpoint] "
|
|
4
|
+
labels: ["registry"]
|
|
5
|
+
body:
|
|
6
|
+
- type: markdown
|
|
7
|
+
attributes:
|
|
8
|
+
value: |
|
|
9
|
+
Thank you. If we recorded your endpoint as unreachable and it is not, we would rather be
|
|
10
|
+
corrected than counted right. This has already happened once: a live payer endpoint was
|
|
11
|
+
logged as dead because a middlebox on the probing network intercepted TLS.
|
|
12
|
+
|
|
13
|
+
Only public, unauthenticated surfaces are graded. We never register for API access,
|
|
14
|
+
never authenticate, and never request patient data.
|
|
15
|
+
- type: input
|
|
16
|
+
id: organization
|
|
17
|
+
attributes:
|
|
18
|
+
label: Organization
|
|
19
|
+
placeholder: Example Health Plan
|
|
20
|
+
validations:
|
|
21
|
+
required: true
|
|
22
|
+
- type: input
|
|
23
|
+
id: base_url
|
|
24
|
+
attributes:
|
|
25
|
+
label: FHIR base URL
|
|
26
|
+
description: "The base, not the metadata path. We append /metadata ourselves."
|
|
27
|
+
placeholder: https://fhir.example.com/r4
|
|
28
|
+
validations:
|
|
29
|
+
required: true
|
|
30
|
+
- type: dropdown
|
|
31
|
+
id: kind
|
|
32
|
+
attributes:
|
|
33
|
+
label: Category
|
|
34
|
+
description: Grades are only comparable within a category.
|
|
35
|
+
options:
|
|
36
|
+
- Payer Patient Access API
|
|
37
|
+
- Payer Provider Directory API
|
|
38
|
+
- Provider or health system API
|
|
39
|
+
- EHR vendor sandbox
|
|
40
|
+
- Reference or test server
|
|
41
|
+
validations:
|
|
42
|
+
required: true
|
|
43
|
+
- type: dropdown
|
|
44
|
+
id: fhir_release
|
|
45
|
+
attributes:
|
|
46
|
+
label: FHIR release
|
|
47
|
+
description: Endpoints are graded against the release they intend to serve.
|
|
48
|
+
options: ["R4", "R5", "STU3"]
|
|
49
|
+
validations:
|
|
50
|
+
required: true
|
|
51
|
+
- type: input
|
|
52
|
+
id: documentation
|
|
53
|
+
attributes:
|
|
54
|
+
label: Public documentation URL
|
|
55
|
+
description: >
|
|
56
|
+
Where this base URL is published. This is how we confirm the publisher is who the entry
|
|
57
|
+
claims, which is what "verified" means here. Entries without it are not added.
|
|
58
|
+
placeholder: https://example.com/developers
|
|
59
|
+
validations:
|
|
60
|
+
required: true
|
|
61
|
+
- type: textarea
|
|
62
|
+
id: context
|
|
63
|
+
attributes:
|
|
64
|
+
label: Anything else
|
|
65
|
+
description: Corrections to an existing entry, or context on what we got wrong.
|
|
66
|
+
- type: checkboxes
|
|
67
|
+
id: confirm
|
|
68
|
+
attributes:
|
|
69
|
+
label: Please confirm
|
|
70
|
+
options:
|
|
71
|
+
- label: This base URL is intended to be publicly reachable without authentication
|
|
72
|
+
required: true
|
|
73
|
+
- label: I am not asking you to authenticate, register, or request patient data
|
|
74
|
+
required: true
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
name: Bug report
|
|
2
|
+
description: Something behaves differently than documented
|
|
3
|
+
labels: ["bug"]
|
|
4
|
+
body:
|
|
5
|
+
- type: markdown
|
|
6
|
+
attributes:
|
|
7
|
+
value: |
|
|
8
|
+
Thanks for taking the time. The most useful reports say what you ran,
|
|
9
|
+
what happened, and what you expected instead.
|
|
10
|
+
|
|
11
|
+
If this is a security vulnerability, please do not file it here. See
|
|
12
|
+
SECURITY.md for how to report it privately.
|
|
13
|
+
- type: textarea
|
|
14
|
+
id: what-happened
|
|
15
|
+
attributes:
|
|
16
|
+
label: What happened
|
|
17
|
+
description: >-
|
|
18
|
+
What you ran and what came back. Paste the output rather than describing it.
|
|
19
|
+
validations:
|
|
20
|
+
required: true
|
|
21
|
+
- type: textarea
|
|
22
|
+
id: expected
|
|
23
|
+
attributes:
|
|
24
|
+
label: What you expected instead
|
|
25
|
+
description: >-
|
|
26
|
+
If a rule or spec section says otherwise, quoting it helps a lot.
|
|
27
|
+
validations:
|
|
28
|
+
required: true
|
|
29
|
+
- type: textarea
|
|
30
|
+
id: input
|
|
31
|
+
attributes:
|
|
32
|
+
label: The endpoint
|
|
33
|
+
description: >-
|
|
34
|
+
The endpoint URL as it appears in the registry, if it is public.
|
|
35
|
+
render: text
|
|
36
|
+
validations:
|
|
37
|
+
required: false
|
|
38
|
+
- type: input
|
|
39
|
+
id: version
|
|
40
|
+
attributes:
|
|
41
|
+
label: Version
|
|
42
|
+
description: >-
|
|
43
|
+
The scorecard page or commit you saw this on
|
|
44
|
+
validations:
|
|
45
|
+
required: true
|
|
46
|
+
- type: textarea
|
|
47
|
+
id: anything-else
|
|
48
|
+
attributes:
|
|
49
|
+
label: Anything else
|
|
50
|
+
description: >-
|
|
51
|
+
Environment, workarounds you tried, related issues.
|
|
52
|
+
validations:
|
|
53
|
+
required: false
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
blank_issues_enabled: true
|
|
2
|
+
contact_links:
|
|
3
|
+
- name: How grades are calculated
|
|
4
|
+
url: https://fhir.chelseakr.com/how-we-grade/
|
|
5
|
+
about: Every finding code, what it checks, and the spec clause it cites
|
|
6
|
+
- name: Why some payers cannot be checked publicly
|
|
7
|
+
url: https://github.com/ChelseaKR/fhir-scorecard/blob/main/docs/payer-verifiability.md
|
|
8
|
+
about: The write-up, including the measurement errors this project made and corrected
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
name: Idea or feature request
|
|
2
|
+
description: Suggest something this should do that it does not
|
|
3
|
+
labels: ["enhancement"]
|
|
4
|
+
body:
|
|
5
|
+
- type: markdown
|
|
6
|
+
attributes:
|
|
7
|
+
value: |
|
|
8
|
+
Ideas are welcome, including ones that turn out to be a bad fit. If you
|
|
9
|
+
are unsure whether something is a bug or intended behavior, open a
|
|
10
|
+
discussion instead and we can work it out there.
|
|
11
|
+
- type: textarea
|
|
12
|
+
id: problem
|
|
13
|
+
attributes:
|
|
14
|
+
label: The problem
|
|
15
|
+
description: >-
|
|
16
|
+
What are you trying to do that is hard or impossible right now?
|
|
17
|
+
validations:
|
|
18
|
+
required: true
|
|
19
|
+
- type: textarea
|
|
20
|
+
id: proposal
|
|
21
|
+
attributes:
|
|
22
|
+
label: What you have in mind
|
|
23
|
+
description: >-
|
|
24
|
+
A rough shape is fine. Alternatives you considered are useful too.
|
|
25
|
+
validations:
|
|
26
|
+
required: false
|
|
27
|
+
- type: checkboxes
|
|
28
|
+
id: willing
|
|
29
|
+
attributes:
|
|
30
|
+
label: Would you want to build it?
|
|
31
|
+
description: >-
|
|
32
|
+
Entirely optional, and a no is a perfectly good answer.
|
|
33
|
+
options:
|
|
34
|
+
- label: I would be interested in opening a PR for this
|
|
35
|
+
required: false
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
name: Dispute or remove an entry
|
|
2
|
+
description: Ask us to correct or take down something about your organization
|
|
3
|
+
title: "[dispute] "
|
|
4
|
+
labels: ["registry", "dispute"]
|
|
5
|
+
body:
|
|
6
|
+
- type: markdown
|
|
7
|
+
attributes:
|
|
8
|
+
value: |
|
|
9
|
+
This project measures public surfaces and takes a non-adversarial posture. If an entry is
|
|
10
|
+
wrong, or you would rather not be listed, say so and we will correct or remove it.
|
|
11
|
+
We do not require you to prove anything first.
|
|
12
|
+
- type: input
|
|
13
|
+
id: endpoint
|
|
14
|
+
attributes:
|
|
15
|
+
label: Which entry
|
|
16
|
+
placeholder: "endpoint id or organization name"
|
|
17
|
+
validations:
|
|
18
|
+
required: true
|
|
19
|
+
- type: dropdown
|
|
20
|
+
id: request
|
|
21
|
+
attributes:
|
|
22
|
+
label: What are you asking for
|
|
23
|
+
options:
|
|
24
|
+
- Correct a fact
|
|
25
|
+
- Remove the entry
|
|
26
|
+
- Something else
|
|
27
|
+
validations:
|
|
28
|
+
required: true
|
|
29
|
+
- type: textarea
|
|
30
|
+
id: detail
|
|
31
|
+
attributes:
|
|
32
|
+
label: Details
|
|
33
|
+
validations:
|
|
34
|
+
required: true
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
3114598+ChelseaKR@users.noreply.github.com namespaces="git" ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIIOjn/aI0d9jElCoi7qT4+6j9UmgTH7vLGAqJXiKMoCE
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# Dependency scanning and update PRs (SECURITY-AND-SUPPLY-CHAIN-STANDARD).
|
|
2
|
+
# Runtime dependencies are stdlib-only; this watches the dev toolchain and the
|
|
3
|
+
# SHA-pinned GitHub Actions.
|
|
4
|
+
version: 2
|
|
5
|
+
updates:
|
|
6
|
+
# `uv`, not `pip`. This project's dependency surface is a PEP 735 `[dependency-groups]`
|
|
7
|
+
# block resolved into `uv.lock`; `[project] dependencies` is empty. The `pip` ecosystem
|
|
8
|
+
# does not read `[dependency-groups]`, and a bump that did not also update `uv.lock`
|
|
9
|
+
# would fail `make verify`, which opens with `uv lock --check`.
|
|
10
|
+
#
|
|
11
|
+
# The symptom was silence, not red PRs. Every dependabot pull request ever opened on this
|
|
12
|
+
# repository - twelve of them, 2026-08-07 to 2026-08-27, on a weekly schedule - is
|
|
13
|
+
# `github-actions`. Zero are `pip`, across a window in which pytest, mypy, ruff, pip-audit
|
|
14
|
+
# and hypothesis all released. The dev toolchain the README calls "the whole dependency
|
|
15
|
+
# surface" was unwatched, and nothing said so.
|
|
16
|
+
#
|
|
17
|
+
# `uv` is a documented `package-ecosystem` value: GitHub's Dependabot options reference
|
|
18
|
+
# lists it, and version updates went generally available for it on 2025-03-13, security
|
|
19
|
+
# updates on 2025-12-16. `uv.lock` is committed, which is what the ecosystem reads.
|
|
20
|
+
- package-ecosystem: "uv"
|
|
21
|
+
directory: "/"
|
|
22
|
+
schedule:
|
|
23
|
+
interval: "weekly"
|
|
24
|
+
- package-ecosystem: "github-actions"
|
|
25
|
+
directory: "/"
|
|
26
|
+
schedule:
|
|
27
|
+
interval: "weekly"
|
|
28
|
+
groups:
|
|
29
|
+
# `security.yml` pins github/codeql-action/init and github/codeql-action/analyze to
|
|
30
|
+
# the same commit, and CodeQL refuses to run when the two disagree: "Loaded a
|
|
31
|
+
# configuration file for version X, but running version Y". Dependabot treats the two
|
|
32
|
+
# actions as separate dependencies, so ungrouped it opens one PR per action and each
|
|
33
|
+
# one, in isolation, makes the versions disagree. Both PRs are then born red through
|
|
34
|
+
# no fault of their own, and whichever merges first leaves `main` red until the other
|
|
35
|
+
# follows. That happened on the 4.37.6 to 4.37.7 bump (#43 merged before #41) and
|
|
36
|
+
# again on 4.37.7 to 4.37.8 (#51, #52).
|
|
37
|
+
#
|
|
38
|
+
# Grouping them means one PR moves both pins together, which is the only state CodeQL
|
|
39
|
+
# accepts.
|
|
40
|
+
codeql-action:
|
|
41
|
+
patterns:
|
|
42
|
+
- "github/codeql-action*"
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
name: Compliance report bundle
|
|
2
|
+
|
|
3
|
+
# The compliance-bundle tier's fulfillment step (docs/compliance-bundle-plan.md): render one
|
|
4
|
+
# buyer's branded evidence reports for a cohort of endpoints, zip them with a manifest, put the
|
|
5
|
+
# archive behind a 30-day capability link, and email the link. GitHub Actions is the on-demand
|
|
6
|
+
# compute, so the tier needs no always-on server.
|
|
7
|
+
#
|
|
8
|
+
# Dispatched by infra/compliance-bundle's post-checkout setup Lambda. It can also be dispatched
|
|
9
|
+
# by hand, on main, to re-run an order: the repair for an undelivered one is a re-run with the
|
|
10
|
+
# same order_ref. Payment is settled before dispatch; this workflow never talks to Stripe.
|
|
11
|
+
#
|
|
12
|
+
# NOTHING ABOUT THE BUYER IS AN INPUT. This repository is public, and GitHub prints each step's
|
|
13
|
+
# environment -- including any value that came from a workflow_dispatch input -- in a run log
|
|
14
|
+
# anyone can read. An earlier draft took the buyer's email address, organization name, endpoint
|
|
15
|
+
# list, and the bundle id (the download capability) as inputs, and would have published every
|
|
16
|
+
# one of them for every order. The only input now is `order_ref`: a random 128-bit name for an
|
|
17
|
+
# object the setup Lambda wrote to the private artifacts bucket. On its own it grants nothing;
|
|
18
|
+
# reading the object needs this workflow's AWS role, which trusts runs on main only. Every value
|
|
19
|
+
# read from the object is registered with ::add-mask:: before any later step can print it, so an
|
|
20
|
+
# error message that happens to quote an address is masked too.
|
|
21
|
+
#
|
|
22
|
+
# Renders from the already-published dataset, never re-probes. A bundle is packaging for the
|
|
23
|
+
# free site's own numbers, not a second measurement, so this fetches
|
|
24
|
+
# https://fhir.chelseakr.com/scorecards.json -- the same file a free visitor reads -- rather than
|
|
25
|
+
# re-grading, which would re-probe every payer's endpoint on every purchase and risk a report
|
|
26
|
+
# that disagrees with the free page for the same endpoint on the same day.
|
|
27
|
+
|
|
28
|
+
on:
|
|
29
|
+
workflow_dispatch:
|
|
30
|
+
inputs:
|
|
31
|
+
order_ref:
|
|
32
|
+
description: "32 lowercase hex characters naming a stored order; carries no buyer data"
|
|
33
|
+
required: true
|
|
34
|
+
type: string
|
|
35
|
+
|
|
36
|
+
permissions:
|
|
37
|
+
contents: read
|
|
38
|
+
|
|
39
|
+
# Scoped per order rather than global: GitHub keeps only one pending run per concurrency group,
|
|
40
|
+
# so a shared group would let a third arrival evict a queued, paid order. Scoped to one order, an
|
|
41
|
+
# eviction can only ever drop a duplicate run of the same build. order_ref is safe to name here
|
|
42
|
+
# because it carries nothing.
|
|
43
|
+
concurrency:
|
|
44
|
+
group: compliance-bundle-${{ inputs.order_ref }}
|
|
45
|
+
cancel-in-progress: false
|
|
46
|
+
|
|
47
|
+
jobs:
|
|
48
|
+
bundle:
|
|
49
|
+
runs-on: ubuntu-latest
|
|
50
|
+
timeout-minutes: 20
|
|
51
|
+
permissions:
|
|
52
|
+
contents: read
|
|
53
|
+
id-token: write # read the order and write the archive through AWS OIDC
|
|
54
|
+
steps:
|
|
55
|
+
# A paid order has nowhere to go without these three, so their absence fails the run
|
|
56
|
+
# (and the run's failure is what tells the owner) rather than building an archive nobody
|
|
57
|
+
# can reach.
|
|
58
|
+
- name: Refuse to start without the delivery configuration
|
|
59
|
+
shell: bash
|
|
60
|
+
env:
|
|
61
|
+
ARTIFACTS_BUCKET: ${{ vars.ARTIFACTS_BUCKET }}
|
|
62
|
+
BUNDLE_API_BASE: ${{ vars.BUNDLE_API_BASE }}
|
|
63
|
+
SES_FROM: ${{ vars.SES_FROM }}
|
|
64
|
+
ORDER_REF: ${{ inputs.order_ref }}
|
|
65
|
+
run: |
|
|
66
|
+
set -euo pipefail
|
|
67
|
+
if [ -z "${ARTIFACTS_BUCKET}" ] || [ -z "${BUNDLE_API_BASE}" ] || [ -z "${SES_FROM}" ]; then
|
|
68
|
+
echo "::error::ARTIFACTS_BUCKET, BUNDLE_API_BASE and SES_FROM must all be set as repository variables before an order can be fulfilled. See docs/compliance-bundle-owner-steps.md."
|
|
69
|
+
exit 1
|
|
70
|
+
fi
|
|
71
|
+
if ! [[ "${ORDER_REF}" =~ ^[a-f0-9]{32}$ ]]; then
|
|
72
|
+
echo "::error::order_ref must be 32 lowercase hex characters."
|
|
73
|
+
exit 1
|
|
74
|
+
fi
|
|
75
|
+
|
|
76
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
77
|
+
with:
|
|
78
|
+
persist-credentials: false
|
|
79
|
+
- uses: astral-sh/setup-uv@c18668ad3cf93ea998bef934396af7bb5c839dc7 # v10.2.0
|
|
80
|
+
with:
|
|
81
|
+
python-version: "3.12"
|
|
82
|
+
- name: Install the locked environment
|
|
83
|
+
shell: bash
|
|
84
|
+
run: |
|
|
85
|
+
set -euo pipefail
|
|
86
|
+
uv sync --locked
|
|
87
|
+
|
|
88
|
+
- name: Authenticate to AWS
|
|
89
|
+
uses: aws-actions/configure-aws-credentials@e1253824e5c10ff9df46874f81ed3ec929e19cfd # v6.3.0
|
|
90
|
+
with:
|
|
91
|
+
role-to-assume: ${{ secrets.AWS_ROLE_ARN }}
|
|
92
|
+
aws-region: ${{ vars.AWS_REGION || 'us-west-2' }}
|
|
93
|
+
|
|
94
|
+
# The object is read into request.json and every buyer-supplied value in it is masked
|
|
95
|
+
# before anything else runs. The masking happens inside Python reading the file, so no
|
|
96
|
+
# value ever appears in a step's rendered script or environment block.
|
|
97
|
+
- name: Collect the order and mask what it holds
|
|
98
|
+
shell: bash
|
|
99
|
+
env:
|
|
100
|
+
ARTIFACTS_BUCKET: ${{ vars.ARTIFACTS_BUCKET }}
|
|
101
|
+
ORDER_REF: ${{ inputs.order_ref }}
|
|
102
|
+
run: |
|
|
103
|
+
set -euo pipefail
|
|
104
|
+
aws s3 cp "s3://${ARTIFACTS_BUCKET}/compliance-requests/${ORDER_REF}.json" request.json --only-show-errors
|
|
105
|
+
uv run python -m fhir_scorecard.bundle_order mask request.json
|
|
106
|
+
|
|
107
|
+
# The published dataset, fetched fresh rather than trusted from the checkout: the live
|
|
108
|
+
# site is rebuilt daily on a schedule independent of commits (pages.yml), and a bundle
|
|
109
|
+
# must render the numbers a buyer could see on fhir.chelseakr.com today. `curl -f` fails
|
|
110
|
+
# the run on anything but a 2xx: a dataset that could not be read must never render as
|
|
111
|
+
# "no scorecard is published" for an endpoint that has one.
|
|
112
|
+
- name: Fetch the published dataset
|
|
113
|
+
shell: bash
|
|
114
|
+
run: |
|
|
115
|
+
set -euo pipefail
|
|
116
|
+
curl -fsSL --retry 3 --retry-delay 5 -o scorecards.json https://fhir.chelseakr.com/scorecards.json
|
|
117
|
+
|
|
118
|
+
- name: Render the bundle
|
|
119
|
+
shell: bash
|
|
120
|
+
run: |
|
|
121
|
+
set -euo pipefail
|
|
122
|
+
max_endpoints="$(uv run python -m fhir_scorecard.bundle_order cap request.json)"
|
|
123
|
+
uv run fhir-scorecard bundle --request request.json \
|
|
124
|
+
--registry data/registry.json --scorecards scorecards.json \
|
|
125
|
+
--max-endpoints "${max_endpoints}" \
|
|
126
|
+
--out bundle.zip --plan-out manifest.json
|
|
127
|
+
included="$(jq '.included' manifest.json)"
|
|
128
|
+
requested="$(jq '.requested' manifest.json)"
|
|
129
|
+
{
|
|
130
|
+
echo "## Compliance report bundle"
|
|
131
|
+
echo
|
|
132
|
+
echo "${included} of ${requested} requested endpoints included; the manifest says"
|
|
133
|
+
echo "what happened to the rest. Nothing identifying the order is shown on this page."
|
|
134
|
+
} >> "$GITHUB_STEP_SUMMARY"
|
|
135
|
+
|
|
136
|
+
# compliance-bundles/ expires after 30 days (main.tf's lifecycle rule). The only way to it
|
|
137
|
+
# is the download route in infra/compliance-bundle, which presigns per click.
|
|
138
|
+
- name: Upload the archive behind its capability key
|
|
139
|
+
shell: bash
|
|
140
|
+
env:
|
|
141
|
+
ARTIFACTS_BUCKET: ${{ vars.ARTIFACTS_BUCKET }}
|
|
142
|
+
run: |
|
|
143
|
+
set -euo pipefail
|
|
144
|
+
key="$(uv run python -m fhir_scorecard.bundle_order archive-key request.json)"
|
|
145
|
+
aws s3 cp bundle.zip "s3://${ARTIFACTS_BUCKET}/${key}" \
|
|
146
|
+
--content-type application/zip --only-show-errors
|
|
147
|
+
|
|
148
|
+
- name: Email the download link
|
|
149
|
+
shell: bash
|
|
150
|
+
env:
|
|
151
|
+
BUNDLE_API_BASE: ${{ vars.BUNDLE_API_BASE }}
|
|
152
|
+
SES_FROM: ${{ vars.SES_FROM }}
|
|
153
|
+
run: |
|
|
154
|
+
set -euo pipefail
|
|
155
|
+
uv run --with boto3 python -m fhir_scorecard.bundle_order email request.json manifest.json
|
|
156
|
+
|
|
157
|
+
# What this may NOT do is name the order: the bundle id is the download credential, and
|
|
158
|
+
# annotations and run summaries are public on a public repository. This says only that an
|
|
159
|
+
# order failed and how to repair it.
|
|
160
|
+
- name: Say that a paid order failed
|
|
161
|
+
if: ${{ failure() }}
|
|
162
|
+
shell: bash
|
|
163
|
+
env:
|
|
164
|
+
ORDER_REF: ${{ inputs.order_ref }}
|
|
165
|
+
run: |
|
|
166
|
+
set -euo pipefail
|
|
167
|
+
echo "::error::A paid compliance report bundle did not complete. The buyer was told the build had started and nothing else will tell them otherwise. Re-running this workflow on main with the same order_ref is the repair."
|
|
168
|
+
{
|
|
169
|
+
echo
|
|
170
|
+
echo "## A paid order was not delivered"
|
|
171
|
+
echo
|
|
172
|
+
echo "- order_ref: \`${ORDER_REF}\` (names the stored order; carries no buyer data)"
|
|
173
|
+
echo
|
|
174
|
+
echo "Re-running this workflow with the same order_ref is safe: the archive and the"
|
|
175
|
+
echo "download link are both keyed on the bundle id inside the stored order, so a"
|
|
176
|
+
echo "re-run fills the object the buyer's existing link already points at."
|
|
177
|
+
} >> "$GITHUB_STEP_SUMMARY"
|
|
178
|
+
|
|
179
|
+
# Deliberately no upload-artifact step. A run artifact of this repository is published:
|
|
180
|
+
# every signed-in GitHub account can download it for its whole retention window. bundle.zip
|
|
181
|
+
# is the paid deliverable and manifest.json and request.json carry the download capability
|
|
182
|
+
# and the buyer's address.
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
# Is the site still the site this repository publishes, and is it still being published?
|
|
2
|
+
#
|
|
3
|
+
# grade-and-publish runs `audit-site` on the local site/ directory before the upload,
|
|
4
|
+
# and the deploy job returns. After that nothing has ever looked at the bytes a reader
|
|
5
|
+
# receives. A publish that failed, an upload that dropped an asset, or a Pages setting
|
|
6
|
+
# that stopped serving would leave every gate green while the live site was stale,
|
|
7
|
+
# broken, or gone, and nothing in this repository could tell.
|
|
8
|
+
#
|
|
9
|
+
# This check is narrower than its siblings on purpose. Most of this site is a daily
|
|
10
|
+
# rescore of every live third-party endpoint in the registry, every page footer carries a minute-
|
|
11
|
+
# resolution Generated stamp, and the availability and history pages derive from
|
|
12
|
+
# data/history.json, which CI restores from the capability-history branch rather than
|
|
13
|
+
# from main. Rebuilding that here would mean re-probing every registry endpoint to produce
|
|
14
|
+
# numbers that legitimately differ from the published ones, which is a moving target
|
|
15
|
+
# and would produce noise rather than signal.
|
|
16
|
+
#
|
|
17
|
+
# So it checks what IS a pure function of committed inputs, exactly: all 58 files under
|
|
18
|
+
# src/fhir_scorecard/assets, which write_assets copies verbatim; robots.txt and
|
|
19
|
+
# dataset.schema.json, which are pure functions of the origin string; and the identity
|
|
20
|
+
# half of api/index.json and dataset.csv, meaning the endpoint set and every field that
|
|
21
|
+
# comes from data/registry.json rather than from a probe.
|
|
22
|
+
#
|
|
23
|
+
# One rendered page is read, for four tags. The home page's og:image and twitter:image
|
|
24
|
+
# are site.social_card_url(origin) and nothing else, and og:title, og:description and
|
|
25
|
+
# og:image:alt have to be there. They carry no grade, latency or timestamp, so they are
|
|
26
|
+
# as pure as the two documents above -- and a head naming a card the deployment does not
|
|
27
|
+
# serve is invisible from inside a checkout and blank everywhere the page is shared.
|
|
28
|
+
#
|
|
29
|
+
# Plus the one thing no rebuild would catch and no audit does: the site has to be
|
|
30
|
+
# recent. A site frozen a year ago still audits clean, so api/index.json's generated_at
|
|
31
|
+
# must parse, must not be in the future, and must be inside 48 hours of the run.
|
|
32
|
+
#
|
|
33
|
+
# It reads the network, deliberately, which is why it holds only `contents: read`, is
|
|
34
|
+
# its own workflow, and is not a required check: it grades the deployment, and a
|
|
35
|
+
# deployment that has not happened yet is not a reason to block a merge.
|
|
36
|
+
#
|
|
37
|
+
# Runs daily and on demand (Actions > live integrity sentinel > Run workflow). The cron
|
|
38
|
+
# sits well after grade-and-publish's 14:17 so it reads a settled deployment -- but it
|
|
39
|
+
# also sits five hours and fifty minutes before the next one, and a change merged in that
|
|
40
|
+
# window is on main and not yet on the site. That is 24% of the clock, and the working
|
|
41
|
+
# part of it. It used to be reported as a failure: 1 of the 1 reds this check had by
|
|
42
|
+
# 2026-09-12 was exactly that, #120 merged at 16:24 after the 14:27 publish. The tool now
|
|
43
|
+
# dates the newest commit touching a checked input and calls a site that predates it a
|
|
44
|
+
# pending publish rather than a fault, which is why the checkout below is not shallow.
|
|
45
|
+
name: live integrity sentinel
|
|
46
|
+
|
|
47
|
+
on:
|
|
48
|
+
schedule:
|
|
49
|
+
- cron: "7 20 * * *"
|
|
50
|
+
workflow_dispatch:
|
|
51
|
+
|
|
52
|
+
permissions:
|
|
53
|
+
contents: read
|
|
54
|
+
|
|
55
|
+
concurrency:
|
|
56
|
+
group: live-integrity
|
|
57
|
+
cancel-in-progress: false
|
|
58
|
+
|
|
59
|
+
jobs:
|
|
60
|
+
verify-live:
|
|
61
|
+
name: the live site still matches its committed inputs
|
|
62
|
+
runs-on: ubuntu-latest
|
|
63
|
+
timeout-minutes: 10
|
|
64
|
+
steps:
|
|
65
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
66
|
+
with:
|
|
67
|
+
ref: main
|
|
68
|
+
persist-credentials: false
|
|
69
|
+
# Full history, because the check asks `git log` when a checked input last
|
|
70
|
+
# changed and the default depth of 1 cannot answer. A shallow clone grafts its
|
|
71
|
+
# oldest fetched commit into a parentless root, so at depth 1 every file in the
|
|
72
|
+
# tree reads as having been added at HEAD: the inputs would date to the newest
|
|
73
|
+
# commit on main whatever it touched, and any difference at all would be excused
|
|
74
|
+
# as a publish that has not run yet. verify_live_site.py refuses a parentless
|
|
75
|
+
# answer for that reason, so a shallow checkout does not weaken the check -- it
|
|
76
|
+
# loses the distinction entirely and every merge-window difference goes back to
|
|
77
|
+
# being a spurious red. tests/test_live_integrity_pending_publish.py asserts this.
|
|
78
|
+
fetch-depth: 0
|
|
79
|
+
|
|
80
|
+
- uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
|
|
81
|
+
with:
|
|
82
|
+
python-version: "3.12"
|
|
83
|
+
|
|
84
|
+
- name: Compare the live site with this checkout's committed inputs
|
|
85
|
+
run: python3 tools/verify_live_site.py
|