Skip to content

QA plan: Corpus license and attribution (#48)

Story: Corpus license and attribution (#48)
Capability: Licensing and attribution (#47)
Related: Legal and compliance (#46); security per-feature requirements (#46/#47/#48)

TypeCoverage
e2e / componentThe Apache-2.0 attribution for neural-bridge/rag-dataset-12000 is rendered in the SPA (footer or About section); Playwright asserts the text is present in the DOM
e2e / componentThe attribution text is present on the QA CloudFront URL (not just in the bundle, but as rendered content)
CISBOM generation step produces a CycloneDX SBOM (sbom.json or sbom.xml) on every PR
CISBOM license scan step flags any copyleft license (GPL, AGPL, LGPL) on a production runtime dependency as a blocking CI failure
CIPermissive licenses (MIT, Apache-2.0, BSD) pass the SBOM scan without blocking
DocumentationThe architecture overview or cost.md contains the attribution sentence (not just the SPA)
  • Story #17 (React chat UI) merged — SPA must exist to add the attribution element
  • Story #29 (CI pipeline) includes a SBOM generation step (cyclonedx-bom or pip-licenses + cyclonedx-py)
  • Playwright: assertion that data-testid="corpus-attribution" element is visible and contains “Apache-2.0” and “neural-bridge/rag-dataset-12000” (or equivalent text)
  • CI SBOM: sbom.json is generated and committed as a CI artifact on every PR
  • CI license scan: a test PR with a fake GPL dependency in pyproject.toml (dev group, not runtime) confirmed to either block or pass correctly based on the runtime vs. dev scope distinction
  • Documentation: grep for “Apache-2.0” in the architecture overview page passes

Playwright: QA CloudFront URL. CI: GitHub Actions for SBOM generation and scan. Documentation check: local or CI grep.

Playwright, cyclonedx-py or pip-licenses, a license-check script (or liccheck), grep.

// Given the QA SPA is loaded in Playwright
await page.goto(process.env.QA_SPA_URL);
// When the page settles
await page.waitForLoadState('networkidle');
// Then the corpus attribution element is visible and contains the required text
const attribution = page.getByTestId('corpus-attribution');
await expect(attribution).toBeVisible();
await expect(attribution).toContainText('Apache-2.0');
await expect(attribution).toContainText('neural-bridge/rag-dataset-12000');

SBOM license check (CI):

Terminal window
# Given the SBOM for the current PR has been generated
# When the license scanner parses it for copyleft licenses
python3 scripts/check_licenses.py sbom.json --fail-on "GPL,AGPL,LGPL" --runtime-only
# Then no runtime dependency carries a copyleft license
  • The corpus attribution requirement applies to the rendered SPA, not just a comment in the code. If the attribution element is conditionally rendered (e.g., only when the SPA is connected to the API), the Playwright test must trigger the condition first or render unconditionally.
  • pip-licenses may misclassify transitive dependencies; use the --packages flag restricted to direct runtime dependencies from pyproject.toml production groups to reduce noise.

Security per-feature requirements (#46/#47/#48): Apache-2.0 attribution in SPA and architecture overview; CycloneDX SBOM in CI; copyleft licenses block merge. Exit criteria map to each requirement. No additional security threat model rows apply; the risk is supply-chain license exposure, not a STRIDE threat.