diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 00000000..9f606e58 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,6 @@ +# The container builds only consume files under .devcontainer/ (bind-mounted by +# the Dockerfiles); all other build inputs are fetched from checksum-pinned URLs. +# Exclude everything else from the build context so that no source, credentials, +# caches, or test artifacts can ever be copied into an image layer. +* +!.devcontainer/ diff --git a/.github/workflows/vulnerability-scan.yml b/.github/workflows/vulnerability-scan.yml index 56675382..3262ed17 100644 --- a/.github/workflows/vulnerability-scan.yml +++ b/.github/workflows/vulnerability-scan.yml @@ -14,7 +14,13 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - flavor: ["cpp", "embedded-cpp", "rust"] + include: + - flavor: cpp + dockerfile: .devcontainer/cpp/Dockerfile + - flavor: embedded-cpp + dockerfile: .devcontainer/cpp/Dockerfile + - flavor: rust + dockerfile: .devcontainer/rust/Dockerfile permissions: security-events: write # is needed by github/codeql-action/upload-sarif to upload sarif files steps: @@ -25,7 +31,7 @@ jobs: id: scan with: image: ghcr.io/${{ github.repository }}-${{ matrix.flavor }}:latest - dockerfile: .devcontainer/Dockerfile + dockerfile: ${{ matrix.dockerfile }} - uses: github/codeql-action/upload-sarif@8aad20d150bbac5944a9f9d289da16a4b0d87c1e # v4.36.2 if: steps.scan.outputs.sarif != '' with: diff --git a/.github/workflows/wc-document-generation.yml b/.github/workflows/wc-document-generation.yml index 0683f8cb..d36b99d5 100644 --- a/.github/workflows/wc-document-generation.yml +++ b/.github/workflows/wc-document-generation.yml @@ -28,7 +28,7 @@ jobs: run: | set -Eeuo pipefail - sudo apt-get update && sudo apt-get install --no-install-recommends -y plantuml + sudo apt-get update && sudo apt-get install --no-install-recommends -y graphviz plantuml python -m pip install sbdl==1.22.7 - name: Build & Validate SBDL model run: sbdl -m compile test/cpp/integration-tests.bats test/cpp/features/*.feature test/embedded-cpp/integration-tests.bats test/embedded-cpp/features/*.feature > amp-devcontainer.sbdl @@ -41,15 +41,15 @@ jobs: cat > document-control.sbdl < software-test-plan.md - name: 🧩 Generate RTM document run: sbdl -m template-fill --set-config template_extensions_file docs/templates/jinja-extensions.py --template docs/templates/requirements-traceability-matrix.md.j2 amp-devcontainer.sbdl document-control.sbdl > requirements-traceability-matrix.md + - name: 🛡️ Generate Threat Model document + run: sbdl -m template-fill --set-config template_extensions_file docs/templates/jinja-extensions.py --template docs/templates/threat-model.md.j2 docs/threat-model.sbdl document-control.sbdl > threat-model.md + - name: 📊 Generate Threat Model diagram + run: sbdl -m aspect-diagram docs/threat-model.sbdl -o threat-model-dfd.png - name: 📄 Generate SRS PDF uses: docker://pandoc/extra:3.9.0.0-ubuntu@sha256:72afa9c8d3300e5f10c9c4330e101725687f2179bffd912fb859c6d2ae85de62 with: @@ -70,6 +74,10 @@ jobs: uses: docker://pandoc/extra:3.9.0.0-ubuntu@sha256:72afa9c8d3300e5f10c9c4330e101725687f2179bffd912fb859c6d2ae85de62 with: args: --template eisvogel --syntax-highlighting idiomatic --number-sections --output requirements-traceability-matrix.pdf requirements-traceability-matrix.md + - name: 🛡️ Generate Threat Model PDF + uses: docker://pandoc/extra:3.9.0.0-ubuntu@sha256:72afa9c8d3300e5f10c9c4330e101725687f2179bffd912fb859c6d2ae85de62 + with: + args: --template eisvogel --syntax-highlighting idiomatic --number-sections --output threat-model.pdf threat-model.md - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: documents diff --git a/docs/templates/partials/document-control.md.j2 b/docs/templates/partials/document-control.md.j2 index 817e049c..d7de1262 100644 --- a/docs/templates/partials/document-control.md.j2 +++ b/docs/templates/partials/document-control.md.j2 @@ -1,7 +1,7 @@ -| Property | Value | -|-------------------|---------------------------------------------------------------------------------------------------------------------------| -| Document version | {{ sbdl['doc_control']['custom:version'] }} | -| Generation date | {{ sbdl['doc_control']['custom:generated_at'] | strftime('%Y-%m-%d') }} | -| Source revision | {{ sbdl['doc_control']['custom:git_sha'] }} | -| Source branch/tag | {{ sbdl['doc_control']['custom:git_ref'] }} | -| Model | SBDL {{ sbdl['doc_control']['custom:sbdl_compiler_version'] }} (DSL {{ sbdl['doc_control']['custom:sbdl_dsl_version'] }}) | +| Property | Value | +|-------------------------|---------------------------------------------------------------------------------------------------------------------------| +| Document version | {{ sbdl['doc-control']['custom:version'] }} | +| Generation date | {{ sbdl['doc-control']['custom:generated-at'] | strftime('%Y-%m-%d') }} | +| Source revision | {{ sbdl['doc-control']['custom:git-sha'] }} | +| Source branch/tag | {{ sbdl['doc-control']['custom:git-ref'] }} | +| Model | SBDL {{ sbdl['doc-control']['custom:sbdl-compiler-version'] }} (DSL {{ sbdl['doc-control']['custom:sbdl-dsl-version'] }}) | diff --git a/docs/templates/requirements-traceability-matrix.md.j2 b/docs/templates/requirements-traceability-matrix.md.j2 index 00ad60ec..467147c6 100644 --- a/docs/templates/requirements-traceability-matrix.md.j2 +++ b/docs/templates/requirements-traceability-matrix.md.j2 @@ -2,7 +2,7 @@ title: "Requirements traceability matrix for amp-devcontainer" author: ["@rjaegers"] colorlinks: true -date: "{{ sbdl['doc_control']['custom:generated_at'] | strftime('%Y-%m-%d') }}" +date: "{{ sbdl['doc-control']['custom:generated-at'] | strftime('%Y-%m-%d') }}" keywords: [Traceability, Requirements, RTM, amp-devcontainer] lang: "en" titlepage: true @@ -14,7 +14,7 @@ toc: true toc-own-page: true header-includes: - \AtEndDocument{\label{lastpage}} -{%- if sbdl['doc_control']['custom:is_release'] != 'true' %} +{%- if sbdl['doc-control']['custom:is-release'] != 'true' %} watermark: "DRAFT" {%- endif %} footer-right: "\\thepage \\hspace{1pt} of \\pageref*{lastpage}" diff --git a/docs/templates/software-requirements-specification.md.j2 b/docs/templates/software-requirements-specification.md.j2 index b93bf0d5..63cd358d 100644 --- a/docs/templates/software-requirements-specification.md.j2 +++ b/docs/templates/software-requirements-specification.md.j2 @@ -2,7 +2,7 @@ title: "Software requirements specification for amp-devcontainer" author: ["@rjaegers"] colorlinks: true -date: "{{ sbdl['doc_control']['custom:generated_at'] | strftime('%Y-%m-%d') }}" +date: "{{ sbdl['doc-control']['custom:generated-at'] | strftime('%Y-%m-%d') }}" keywords: [Software, Requirements, SRS, amp-devcontainer] lang: "en" titlepage: true @@ -14,7 +14,7 @@ toc: true toc-own-page: true header-includes: - \AtEndDocument{\label{lastpage}} -{%- if sbdl['doc_control']['custom:is_release'] != 'true' %} +{%- if sbdl['doc-control']['custom:is-release'] != 'true' %} watermark: "DRAFT" {%- endif %} footer-right: "\\thepage \\hspace{1pt} of \\pageref*{lastpage}" diff --git a/docs/templates/software-test-plan.md.j2 b/docs/templates/software-test-plan.md.j2 index 3e473012..3e119d20 100644 --- a/docs/templates/software-test-plan.md.j2 +++ b/docs/templates/software-test-plan.md.j2 @@ -2,7 +2,7 @@ title: "Software test plan for amp-devcontainer" author: ["@rjaegers"] colorlinks: true -date: "{{ sbdl['doc_control']['custom:generated_at'] | strftime('%Y-%m-%d') }}" +date: "{{ sbdl['doc-control']['custom:generated-at'] | strftime('%Y-%m-%d') }}" keywords: [Software, Test, Plan, STP, amp-devcontainer] lang: "en" titlepage: true @@ -14,7 +14,7 @@ toc: true toc-own-page: true header-includes: - \AtEndDocument{\label{lastpage}} -{%- if sbdl['doc_control']['custom:is_release'] != 'true' %} +{%- if sbdl['doc-control']['custom:is-release'] != 'true' %} watermark: "DRAFT" {%- endif %} footer-right: "\\thepage \\hspace{1pt} of \\pageref*{lastpage}" diff --git a/docs/templates/threat-model.md.j2 b/docs/templates/threat-model.md.j2 new file mode 100644 index 00000000..82c1fb06 --- /dev/null +++ b/docs/templates/threat-model.md.j2 @@ -0,0 +1,266 @@ +--- +title: "Threat model for amp-devcontainer" +author: ["@rjaegers"] +colorlinks: true +date: "{{ sbdl['doc-control']['custom:generated-at'] | strftime('%Y-%m-%d') }}" +keywords: [Threat, Model, Security, STRIDE, FMEA, amp-devcontainer] +lang: "en" +titlepage: true +titlepage-color: "0B5ED7" +titlepage-text-color: "FFFFFF" +titlepage-rule-color: "FFFFFF" +titlepage-rule-height: 2 +toc: true +toc-own-page: true +header-includes: + - \AtEndDocument{\label{lastpage}} +{%- if sbdl['doc-control']['custom:is-release'] != 'true' %} +watermark: "DRAFT" +{%- endif %} +footer-right: "\\thepage \\hspace{1pt} of \\pageref*{lastpage}" +... + +{% import "partials/text-utilities.j2" as utils %} +{%- set system = sbdl['system-amp-devcontainer'] -%} + +# Introduction + +## Purpose + +This document describes the security threat model for amp-devcontainer. +It identifies the assets, trust boundaries, and data flows of the system, enumerates the credible threats against it, and records the mitigations that reduce the associated risk to an acceptable level. + +## Scope + +This threat model covers the supply chain and runtime security of the amp-devcontainer container images, their build pipeline, and their distribution. +The following is in scope: + +- The container build pipeline and its execution environment +- Dependency acquisition, pinning, and integrity verification +- Container image signing, publication, and consumption +- The runtime posture of the released container images + +The following is out of scope: + +- Application-level software built using the containers +- Security of third-party services beyond the project's control +- Physical security of developer workstations + +## Methodology + +Threats are identified using the [STRIDE](https://learn.microsoft.com/en-us/azure/security/develop/threat-modeling-tool-threats) classification (Spoofing, Tampering, Repudiation, Information Disclosure, Denial of Service, Elevation of Privilege). + +Each threat is quantified using a Failure Mode and Effects Analysis (FMEA) style Risk Priority Number (RPN): + +$$RPN = S \times O \times D$$ + +where *Severity* ($S$) is a property of the threat's impact, *Occurrence* ($O$) is a property of its attack vector, and *Detectability* ($D$) is a property of the threat itself. Each factor is rated on a scale of 1 (low) to 10 (high). A residual RPN is computed from the post-mitigation occurrence and detectability values to show the effect of the implemented controls. + +The complete model — assets, boundaries, data flows, threats, and mitigations — is expressed in [sbdl](https://sbdl.dev) using custom types layered on the built-in FMEA types, and is versioned alongside the source code. This document is generated from that single source of truth, exactly as the requirements documents are. + +## References + +| Identifier | Title | +|------------|----------------------------------------------------------------------------------------------------------------------------------------| +| STRIDE | [The STRIDE Threat Model](https://learn.microsoft.com/en-us/azure/security/develop/threat-modeling-tool-threats) | +| FMEA | [Failure Mode and Effects Analysis](https://en.wikipedia.org/wiki/Failure_mode_and_effects_analysis) | +| CAPEC | [Common Attack Pattern Enumeration and Classification](https://capec.mitre.org/) | +| CWE | [Common Weakness Enumeration](https://cwe.mitre.org/) | +| SLSA | [Supply-chain Levels for Software Artifacts v1.0](https://slsa.dev/spec/v1.0/levels) | + +## Document Control + +{% include "partials/document-control.md.j2" with context %} + +This document is generated from a formal model defined in [sbdl](https://sbdl.dev) and versioned alongside the source code in Git. +The authoritative source of change history is the [Git log](https://github.com/philips-software/amp-devcontainer/commits/) of the source material from which the model is built. + +# System overview + +{{ utils.reencode(system.description) }} + +| Property | Value | +|-----------------------|----------------------------------------------| +| Business criticality | {{ system['custom:business-criticality'] }} | +| Exposure | {{ system['custom:exposure'] }} | +| Last reviewed | {{ system['custom:reviewed-at'] }} | + +# Trust boundaries + +The system is decomposed into the following trust boundaries. Data crossing a boundary is subject to the threats analysed in this document. + +| Trust boundary | Description | +|----------------|-------------| +{%- for id, item in sbdl.items() if item.type == 'trust-boundary' %} +| {{ item['custom:title'] }} | {{ utils.reencode(item.description) }} | +{%- endfor %} + +## Trust assumptions + +The threat analysis relies on the following assumptions about each trust boundary. + +{% for id, item in sbdl.items() if item.type == 'trust-boundary' -%} +- **{{ item['custom:title'] }}:** {{ utils.reencode(item['custom:assumption']) }} +{% endfor %} +# Actors + +| Actor | Type | Trust boundary | Description | +|-------|------|----------------|-------------| +{%- for id, item in sbdl.items() if item.type == 'actor' %} +| {{ item['custom:title'] }} | {{ item['custom:actor-type'] }} | {{ sbdl[item['parent'][0].identifier]['custom:title'] if 'parent' in item else '—' }} | {{ utils.reencode(item.description) }} | +{%- endfor %} + +# Components + +The processes, servers, and external entities that make up the system. + +| Component | Kind | Trust boundary | Description | +|-----------|------|----------------|-------------| +{%- for id, item in sbdl.items() if item.type in ['process', 'server', 'external-entity'] %} +| {{ item['custom:title'] }} | {{ item.type | replace('-', ' ') }} | {{ sbdl[item['parent'][0].identifier]['custom:title'] if 'parent' in item else '—' }} | {{ utils.reencode(item.description) }} | +{%- endfor %} + +# Data stores + +| Data store | Type | Encrypted | Trust boundary | Description | +|------------|------|-----------|----------------|-------------| +{%- for id, item in sbdl.items() if item.type == 'datastore' %} +| {{ item['custom:title'] }} | {{ item['custom:store-type'] }} | {{ 'yes' if item['custom:encrypted'] is defined and item['custom:encrypted'] == 'true' else 'no' }} | {{ sbdl[item['parent'][0].identifier]['custom:title'] if 'parent' in item else '—' }} | {{ utils.reencode(item.description) }} | +{%- endfor %} + +# Data assets + +| Data asset | Classification | Sensitivity | Description | +|------------|----------------|-------------|-------------| +{%- for id, item in sbdl.items() if item.type == 'data-asset' %} +| {{ item['custom:title'] }} | {{ item['custom:classification'] }} | {{ item['custom:sensitivity'] }} | {{ utils.reencode(item.description) }} | +{%- endfor %} + +# Data flows + +| Data flow | Source | Destination | Protocol | Port | Encrypted | Data asset | +|-----------|--------|-------------|----------|------|-----------|------------| +{%- for id, item in sbdl.items() if item.type == 'dataflow' %} +| {{ item['custom:title'] }} | {{ sbdl[item['custom:source']]['custom:title'] }} | {{ sbdl[item['custom:destination']]['custom:title'] }} | {{ item['custom:protocol'] }} | {{ item['custom:port'] }} | {{ 'yes' if item['custom:encrypted'] == 'true' else 'no' }} | {{ sbdl[item['custom:data']]['custom:title'] if 'custom:data' in item else '—' }} | +{%- endfor %} + +# Data flow diagram + +The diagram below shows the system decomposed into its trust boundaries, with the components, actors, and data stores placed within them, and the data flows linking their sources and destinations. It is generated automatically from the same SBDL model using SBDL's `aspect-diagram` rendering. + +![Data flow diagram for amp-devcontainer, showing trust boundaries, components, actors, data stores, and the data flows between them.](threat-model-dfd.png) + +# Threat analysis +{%- for id, threat in sbdl.items() if threat.type == 'threat' %} +{%- set effect = sbdl[threat['fmea:effect'][0].identifier] %} +{%- set cause = sbdl[threat['fmea:cause'][0].identifier] %} +{%- set control = sbdl[threat['fmea:control'][0].identifier] %} +{%- set severity = effect.severity | int %} +{%- set occurrence = cause.occurrence | int %} +{%- set detect = threat.detectability | int %} +{%- set rpn = severity * occurrence * detect %} +{%- set occ_post = (cause.occurrence_post | int) if 'occurrence_post' in cause else occurrence %} +{%- set det_post = (threat.detectability_post | int) if 'detectability_post' in threat else detect %} +{%- set rpn_post = severity * occ_post * det_post %} + +## {{ threat['custom:threat-id'] }} — {{ utils.reencode(threat['custom:title']) }} + +| Property | Value | +|----------|-------| +| STRIDE category | {{ threat['custom:stride'] }} | +| Qualitative risk | {{ threat['custom:risk-level'] }} | +| Target(s) | {% for a in threat['aspect'] %}{{ sbdl[a.identifier]['custom:title'] }}{% if not loop.last %}, {% endif %}{% endfor %} | +| Severity (S) | {{ severity }} | +| Occurrence (O) | {{ occurrence }} | +| Detectability (D) | {{ detect }} | +| **RPN (S × O × D)** | **{{ rpn }}** | +| Residual RPN | {{ rpn_post }} | +| Weakness (CWE) | {{ threat['custom:cwe'] }} | +| Attack pattern (CAPEC) | {{ threat['custom:capec'] }} | + +**Description** + +{{ utils.reencode(threat.description) }} + +**Attack vector** + +{{ utils.reencode(cause.description) }} + +**Impact** + +{{ utils.reencode(effect.description) }} + +**Mitigation** ({{ control['custom:status'] }}) + +{{ utils.reencode(control.description) }} +{%- endfor %} + +# FMEA risk summary + +The table below ranks all identified threats by their Risk Priority Number (RPN). Higher values indicate higher priority for mitigation. + +{%- set ns = namespace(rows=[]) -%} +{%- for id, threat in sbdl.items() if threat.type == 'threat' -%} +{%- set effect = sbdl[threat['fmea:effect'][0].identifier] -%} +{%- set cause = sbdl[threat['fmea:cause'][0].identifier] -%} +{%- set severity = effect.severity | int -%} +{%- set occurrence = cause.occurrence | int -%} +{%- set detect = threat.detectability | int -%} +{%- set occ_post = (cause.occurrence_post | int) if 'occurrence_post' in cause else occurrence -%} +{%- set det_post = (threat.detectability_post | int) if 'detectability_post' in threat else detect -%} +{%- set _ = ns.rows.append({ + 'tid': threat['custom:threat-id'], + 'stride': threat['custom:stride'], + 'risk': threat['custom:risk-level'], + 's': severity, 'o': occurrence, 'd': detect, + 'rpn': severity * occurrence * detect, + 'rpn_post': severity * occ_post * det_post}) -%} +{%- endfor %} + +| Threat | STRIDE | S | O | D | RPN | Residual RPN | Risk | +|--------|--------|---|---|---|-----|--------------|------| +{%- for row in ns.rows | sort(attribute='rpn', reverse=true) %} +| {{ row.tid }} | {{ row.stride }} | {{ row.s }} | {{ row.o }} | {{ row.d }} | {{ row.rpn }} | {{ row.rpn_post }} | {{ row.risk }} | +{%- endfor %} + +# Control evidence + +Each threat's mitigation is backed by objective, reviewable evidence in the repository, supporting audit and regulatory review. + +| Threat | Control status | Evidence | +|--------|----------------|----------| +{%- for id, threat in sbdl.items() if threat.type == 'threat' %} +{%- set control = sbdl[threat['fmea:control'][0].identifier] %} +| {{ threat['custom:threat-id'] }} | {{ control['custom:status'] }} | {{ utils.reencode(control['custom:evidence']) if 'custom:evidence' in control else '—' }} | +{%- endfor %} + +# Residual risk and planned actions + +The following actions are planned to further reduce residual risk. + +{% for id, item in sbdl.items() if item.type == 'planned-mitigation' -%} +{%- set linked_cause = sbdl[item['fmea:cause'][0].identifier] if 'fmea:cause' in item else none -%} +{%- set linked_threat = sbdl[linked_cause['fmea:mode'][0].identifier] if linked_cause is not none and 'fmea:mode' in linked_cause else none -%} +- **{{ id }}**{% if linked_threat is not none %} (addresses {{ linked_threat['custom:threat-id'] }}){% endif %}: {{ utils.reencode(item.description) }} +{% else -%} +*No outstanding planned actions; all identified threats have implemented mitigations.* +{% endfor %} +# Risk summary + +{%- set counts = namespace(high=0, medium=0, low=0, total=0) -%} +{%- for id, item in sbdl.items() if item.type == 'threat' -%} +{%- set counts.total = counts.total + 1 -%} +{%- if item['custom:risk-level'] == 'High' -%}{%- set counts.high = counts.high + 1 -%} +{%- elif item['custom:risk-level'] == 'Medium' -%}{%- set counts.medium = counts.medium + 1 -%} +{%- else -%}{%- set counts.low = counts.low + 1 -%} +{%- endif -%} +{%- endfor %} + +| Qualitative risk | Count | +|------------------|-------| +| High | {{ counts.high }} | +| Medium | {{ counts.medium }} | +| Low | {{ counts.low }} | +| **Total** | **{{ counts.total }}** | + +Every identified threat has a documented mitigation with traceable evidence, summarised in the Control evidence section. High-risk threats whose controls are only partially implemented carry planned actions listed under Residual risk and planned actions. Residual risk is tracked through the project's standard change control process and re-evaluated whenever the model or its source material changes. diff --git a/docs/threat-model.sbdl b/docs/threat-model.sbdl new file mode 100644 index 00000000..8427dd63 --- /dev/null +++ b/docs/threat-model.sbdl @@ -0,0 +1,967 @@ +#!sbdl +# +# Supply-chain security threat model for amp-devcontainer, expressed in SBDL. +# +# This model maps the threat model for amp-devcontainer onto SBDL, +# consolidating the threat model with the requirements model so that a +# single tool-chain (sbdl) drives all generated documentation. +# +# The STRIDE / threat-modelling concepts are mapped onto SBDL base types as follows: +# +# PyTM / STRIDE concept SBDL custom type SBDL base type +# --------------------- ---------------- -------------- +# Trust boundary / zone trust-boundary aspect +# Actor actor aspect +# External entity external-entity aspect +# Process / component process aspect +# Server server aspect +# Data store datastore aspect +# Data asset / data set data-asset aspect +# Data flow dataflow aspect +# Threat (failure/attack mode) threat fmea:mode +# Attack vector (cause) attack-vector fmea:cause +# Impact (effect) impact fmea:effect +# Mitigation (control) mitigation fmea:control +# Planned mitigation (action) planned-mitigation fmea:action-control +# +# Modelling threats as an FMEA lets the model carry Severity (on the impact), +# Occurrence (on the attack vector) and Detectability (on the threat) so that a +# Risk Priority Number (RPN = S x O x D) can be rendered, mirroring the qualitative +# High/Medium risk levels from the original model. + +# --------------------------------------------------------------------------- +# Custom types +# --------------------------------------------------------------------------- + +customtype trust-boundary is aspect {} +customtype actor is aspect {} +customtype external-entity is aspect {} +customtype process is aspect {} +customtype server is aspect {} +customtype datastore is aspect {} +customtype data-asset is aspect {} +customtype dataflow is aspect {} +customtype threat is fmea:mode {} +customtype attack-vector is fmea:cause {} +customtype impact is fmea:effect {} +customtype mitigation is fmea:control {} +customtype planned-mitigation is fmea:action-control {} + +# --------------------------------------------------------------------------- +# System under analysis +# --------------------------------------------------------------------------- + +system-amp-devcontainer is aspect { + custom:title is "amp-devcontainer" + description is "The amp-devcontainer project provides secure, supply-chain hardened development containers for regulated software development. Key security features include: pinned dependencies with SHA checksums, signed container images with SBOMs, vulnerability scanning with Trivy, OSSF Scorecard compliance, and comprehensive dependency management via Dependabot. The containers support both x64 and arm64 architectures and include development toolchains for C++ (GCC, Clang, ARM GCC) and Rust, along with security analysis tools." + custom:business-criticality is "high" + custom:exposure is "external" + custom:reviewed-at is "2026-07-04" +} + +# --------------------------------------------------------------------------- +# Trust boundaries (trust zones) +# --------------------------------------------------------------------------- + +using { parent is system-amp-devcontainer } + +trust-boundary-public-internet is trust-boundary { + custom:title is "Public Internet" + description is "The untrusted external network over which all third-party sources are reached and from which unauthenticated attackers operate." + custom:assumption is "Treated as fully untrusted; all inbound data is integrity-verified and no confidentiality or authenticity is assumed for anything originating here." +} + +trust-boundary-package-registries is trust-boundary { + custom:title is "Package Registries" + description is "Language and OS package sources such as Ubuntu apt repositories, Python PyPI, and Rust crates.io." + custom:assumption is "Registries are reachable and authentic at the transport layer, but individual packages are untrusted until verified against pinned SHA256 checksums." +} + +trust-boundary-github-marketplace is trust-boundary { + custom:title is "GitHub Marketplace" + description is "Third-party GitHub Actions consumed by the build pipeline." + custom:assumption is "Actions are untrusted third-party code; only commit-SHA-pinned, reviewed actions are executed and their permissions are minimised." +} + +trust-boundary-vendor-sources is trust-boundary { + custom:title is "Vendor Binary Sources" + description is "Vendor and project download sites providing toolchain binaries and archives fetched during the build." + custom:assumption is "Vendor binaries are untrusted until verified by pinned checksum and, where the vendor publishes one, a cryptographic signature." +} + +trust-boundary-vscode-marketplace is trust-boundary { + custom:title is "VS Code Marketplace" + description is "The Visual Studio Code extension marketplace from which development extensions are installed." + custom:assumption is "Extensions are untrusted third-party code; only version-pinned extensions from verified publishers are installed." +} + +trust-boundary-github-infrastructure is trust-boundary { + custom:title is "GitHub Infrastructure" + description is "GitHub's hosted infrastructure including Actions runners, Container Registry, and source code repository." + custom:assumption is "GitHub authenticates identities and enforces RBAC and 2FA, but account or token compromise is assumed to remain possible." +} + +trust-boundary-build-environment is trust-boundary { + custom:title is "Container Build Environment" + description is "GitHub Actions runners executing container builds with elevated privileges." + custom:assumption is "Runners are ephemeral and isolated per build; a single build may be compromised, but compromise must not persist across builds." +} + +trust-boundary-container-runtime is trust-boundary { + custom:title is "Container Runtime Environment" + description is "Developer workstations and CI/CD systems running the devcontainer images." + custom:assumption is "Consumers pull only published images and are expected to verify image signatures and provenance before use." +} + +trust-boundary-developer-workstation is trust-boundary { + custom:title is "Developer Workstation" + description is "Local development environments where developers use the containers." + custom:assumption is "Host integrity is the developer's responsibility; the container reduces but cannot eliminate risk originating on the host." +} + +using { parent is "" } + +# --------------------------------------------------------------------------- +# Actors +# --------------------------------------------------------------------------- + +actor-developer is actor { + custom:title is "Software Developer" + description is "Developers using the devcontainer for local development and testing." + custom:actor-type is "user" + custom:permissions is "Read container images, execute development tools, access source code." + parent is trust-boundary-developer-workstation +} + +actor-ci-cd-system is actor { + custom:title is "CI/CD System" + description is "Automated systems using containers for building and testing software." + custom:actor-type is "system" + custom:permissions is "Pull container images, execute builds, publish artifacts." + parent is trust-boundary-container-runtime +} + +actor-malicious is actor { + custom:title is "Malicious Actor" + description is "Threat actor attempting to compromise the supply chain or development environment." + custom:actor-type is "third_party" + custom:permissions is "None (attempting to gain unauthorized access)." + parent is trust-boundary-public-internet +} + +actor-maintainer is actor { + custom:title is "Project Maintainer" + description is "Authorized maintainers with commit and release permissions." + custom:actor-type is "administrator" + custom:permissions is "Write access to repository, trigger releases, manage security policies." + parent is trust-boundary-github-infrastructure +} + +# --------------------------------------------------------------------------- +# External entities +# --------------------------------------------------------------------------- + +external-entity-package-repos is external-entity { + custom:title is "External Package Repositories" + description is "Ubuntu apt repositories, Python PyPI, Rust crates.io, and other language and OS package sources." + parent is trust-boundary-package-registries +} + +external-entity-github-actions is external-entity { + custom:title is "GitHub Actions Marketplace" + description is "Third-party GitHub Actions referenced by the build workflows." + parent is trust-boundary-github-marketplace +} + +external-entity-vendor-downloads is external-entity { + custom:title is "Vendor Binary Downloads" + description is "Vendor and project download sites providing toolchain binaries such as compilers, analysers, and ccache." + parent is trust-boundary-vendor-sources +} + +external-entity-vscode-marketplace is external-entity { + custom:title is "VS Code Extension Marketplace" + description is "Marketplace source for the pinned Visual Studio Code extensions installed into the environment." + parent is trust-boundary-vscode-marketplace +} + +# --------------------------------------------------------------------------- +# Processes / components +# --------------------------------------------------------------------------- + +process-github-actions-build is process { + custom:title is "GitHub Actions Build Pipeline" + description is "Automated pipeline for building, testing, and publishing container images with security scanning." + parent is trust-boundary-build-environment + custom:repo-link is "https://github.com/philips-software/amp-devcontainer/tree/main/.github/workflows" +} + +process-dependency-mgmt is process { + custom:title is "Dependency Management System" + description is "Comprehensive dependency pinning including apt packages, Python packages, and binary downloads." + parent is trust-boundary-github-infrastructure +} + +process-vscode-extensions is process { + custom:title is "VS Code Extensions Configuration" + description is "Pinned VS Code extensions with specific versions for development environment setup." + parent is trust-boundary-container-runtime +} + +# --------------------------------------------------------------------------- +# Servers +# --------------------------------------------------------------------------- + +server-dockerfile-cpp is server { + custom:title is "C++ Devcontainer Dockerfile" + description is "Multi-stage Dockerfile for building the C++ development environment with GCC, Clang, and embedded toolchains." + parent is trust-boundary-github-infrastructure + custom:os is "Ubuntu" + custom:hardened is "true" + custom:repo-link is "https://github.com/philips-software/amp-devcontainer/blob/main/.devcontainer/cpp/Dockerfile" +} + +server-dockerfile-rust is server { + custom:title is "Rust Devcontainer Dockerfile" + description is "Dockerfile for building the Rust development environment with embedded targets and analysis tools." + parent is trust-boundary-github-infrastructure + custom:os is "Ubuntu" + custom:hardened is "true" + custom:repo-link is "https://github.com/philips-software/amp-devcontainer/blob/main/.devcontainer/rust/Dockerfile" +} + +# --------------------------------------------------------------------------- +# Data stores +# --------------------------------------------------------------------------- + +datastore-source-repository is datastore { + custom:title is "GitHub Source Repository" + description is "Git repository containing source code, build configurations, and security policies." + custom:store-type is "document" + custom:encrypted is "true" + parent is trust-boundary-github-infrastructure +} + +datastore-ghcr-registry is datastore { + custom:title is "GitHub Container Registry" + description is "OCI-compatible registry storing container images with metadata, SBOMs, and vulnerability scan results." + custom:store-type is "object" + custom:encrypted is "true" + parent is trust-boundary-github-infrastructure +} + +datastore-build-cache is datastore { + custom:title is "GitHub Actions Cache" + description is "Build cache storage for Docker layers and build artifacts." + custom:store-type is "key_value" + parent is trust-boundary-build-environment +} + +# --------------------------------------------------------------------------- +# Data assets +# --------------------------------------------------------------------------- + +data-asset-container-images is data-asset { + custom:title is "Container Images" + description is "Signed multi-platform container images with embedded development toolchains." + custom:classification is "SENSITIVE" + custom:sensitivity is "ip" +} + +data-asset-build-artifacts is data-asset { + custom:title is "Build Artifacts and SBOMs" + description is "Software Bill of Materials, vulnerability scan results, and build provenance." + custom:classification is "SENSITIVE" + custom:sensitivity is "biz" +} + +data-asset-source-code is data-asset { + custom:title is "Source Code and Configuration" + description is "Dockerfiles, build scripts, dependency manifests, and security configurations." + custom:classification is "SENSITIVE" + custom:sensitivity is "ip" +} + +# --------------------------------------------------------------------------- +# Data flows +# --------------------------------------------------------------------------- + +dataflow-dependency-download is dataflow { + custom:title is "External Dependency Download" + description is "Download of packages, binaries, and toolchains from external repositories during build." + custom:source is "external-entity-package-repos" + custom:destination is "process-github-actions-build" + custom:protocol is "HTTPS" + custom:port is "443" + custom:encrypted is "true" + related is external-entity-package-repos, process-github-actions-build +} + +dataflow-image-publish is dataflow { + custom:title is "Container Image Publication" + description is "Publishing of built and signed container images to the registry." + custom:source is "process-github-actions-build" + custom:destination is "datastore-ghcr-registry" + custom:protocol is "HTTPS" + custom:port is "443" + custom:encrypted is "true" + custom:data is "data-asset-container-images" + related is process-github-actions-build, datastore-ghcr-registry +} + +dataflow-image-consumption is dataflow { + custom:title is "Container Image Consumption" + description is "Pull of container images by developers and CI/CD systems." + custom:source is "datastore-ghcr-registry" + custom:destination is "actor-developer" + custom:protocol is "HTTPS" + custom:port is "443" + custom:encrypted is "true" + custom:data is "data-asset-container-images" + related is datastore-ghcr-registry, actor-developer +} + +dataflow-source-access is dataflow { + custom:title is "Source Code Access" + description is "Maintainer access to the source code repository for updates and releases." + custom:source is "actor-maintainer" + custom:destination is "datastore-source-repository" + custom:protocol is "HTTPS" + custom:port is "443" + custom:encrypted is "true" + custom:data is "data-asset-source-code" + related is actor-maintainer, datastore-source-repository +} + +dataflow-build-trigger is dataflow { + custom:title is "Build Trigger" + description is "GitHub Actions build triggered by source code changes." + custom:source is "datastore-source-repository" + custom:destination is "process-github-actions-build" + custom:protocol is "HTTPS" + custom:port is "443" + custom:encrypted is "true" + custom:data is "data-asset-source-code" + related is datastore-source-repository, process-github-actions-build +} + +# --------------------------------------------------------------------------- +# Threats (STRIDE), with attack vectors, impacts and mitigations (FMEA) +# --------------------------------------------------------------------------- + +# --- SUPPLY_CHAIN_01: Dependency confusion -------------------------------- + +threat-sc01-dependency-confusion is threat { + custom:title is "Dependency Confusion Attack" + custom:threat-id is "SUPPLY_CHAIN_01" + custom:stride is "Tampering" + custom:risk-level is "High" + custom:capec is "CAPEC-439: Manipulation During Distribution" + custom:cwe is "CWE-494: Download of Code Without Integrity Check" + description is "An attacker uploads malicious packages with names similar to internal dependencies to public repositories, which could be installed during the container build." + remark is "Malicious packages could be installed during container build if dependency management is not properly secured. Affects the dependency management system and the GitHub Actions build pipeline." + detectability is 4 + detectability_post is 3 + aspect is process-dependency-mgmt + fmea:cause is attack-vector-sc01 + fmea:effect is impact-sc01 + fmea:control is mitigation-sc01 +} + +attack-vector-sc01 is attack-vector { + description is "Public package repositories resolve a malicious same-named package in preference to the intended dependency." + occurrence is 4 + occurrence_post is 2 + fmea:mode is threat-sc01-dependency-confusion +} + +impact-sc01 is impact { + description is "Execution of attacker-controlled code inside the build, potentially propagating to all downstream users including safety-critical systems." + severity is 8 + fmea:mode is threat-sc01-dependency-confusion +} + +mitigation-sc01 is mitigation { + custom:status is "Implemented" + custom:evidence is "Version-pinned apt packages in .devcontainer/**/apt-requirements*.json; hash-locked pip installs (--require-hashes) in .devcontainer/cpp/requirements.txt; SHA256-pinned binary downloads in .devcontainer/**/Dockerfile; Dependabot and dependency review in CI." + description is "Mitigations implemented:\n\n- Explicit version pinning of apt packages from documented, trusted sources\n- Hash-locked Python dependencies installed with pip --require-hashes\n- SHA256-pinned direct binary downloads\n- Automated dependency updates via Dependabot and dependency review in CI" + fmea:mode is threat-sc01-dependency-confusion +} + +# --- SUPPLY_CHAIN_02: Compromised base image ------------------------------ + +threat-sc02-base-image is threat { + custom:title is "Compromised Base Image" + custom:threat-id is "SUPPLY_CHAIN_02" + custom:stride is "Tampering" + custom:risk-level is "High" + custom:capec is "CAPEC-439: Manipulation During Distribution" + custom:cwe is "CWE-829: Inclusion of Functionality from Untrusted Source" + description is "The Ubuntu base image contains malicious code or vulnerabilities that propagate to the final container images." + remark is "Base images could contain vulnerabilities or malicious code that propagates to final containers, affecting both the C++ and Rust development environments." + detectability is 3 + detectability_post is 2 + aspect is server-dockerfile-cpp, server-dockerfile-rust + fmea:cause is attack-vector-sc02 + fmea:effect is impact-sc02 + fmea:control is mitigation-sc02 +} + +attack-vector-sc02 is attack-vector { + description is "A mutable base image tag is repointed to a tampered image, or the upstream base image is compromised." + occurrence is 3 + occurrence_post is 2 + fmea:mode is threat-sc02-base-image +} + +impact-sc02 is impact { + description is "Malicious functionality embedded in every derived container image and executed on developer and CI systems." + severity is 8 + fmea:mode is threat-sc02-base-image +} + +mitigation-sc02 is mitigation { + custom:status is "Implemented" + custom:evidence is "Digest-pinned Ubuntu base image in .devcontainer/base/Dockerfile; flavor builds reference amp-devcontainer-base by digest via the BASE_IMAGE build-arg in .github/workflows/build-push-test.yml; daily image scanning (Trivy via crazy-max/ghaction-container-scan) in .github/workflows/vulnerability-scan.yml." + description is "Mitigations implemented:\n\n- Upstream Ubuntu base image pinned to a specific SHA256 digest\n- Flavor builds reference the internal amp-devcontainer-base by content digest, passed as the BASE_IMAGE build-arg from the base image built in the same pipeline run; the mutable :edge default only applies to un-parameterised ad-hoc local builds\n- Published flavor images are self-contained and carry no mutable base reference\n- Daily vulnerability scanning of published images (Trivy via ghaction-container-scan) with SARIF upload\n- Multi-stage builds to reduce attack surface\n- Minimal base images where possible" + fmea:mode is threat-sc02-base-image +} + +# --- RUNTIME_01: Privileged container escape ------------------------------ + +threat-runtime01-priv-escape is threat { + custom:title is "Container Runs With Root Privileges" + custom:threat-id is "RUNTIME_01" + custom:stride is "Elevation of Privilege" + custom:risk-level is "Medium" + custom:capec is "CAPEC-233: Privilege Escalation" + custom:cwe is "CWE-250: Execution with Unnecessary Privileges" + description is "The container images do not define a non-root user, so tools and mounted workspace code run as root inside the container, widening the blast radius of any container breakout or malicious workspace content." + remark is "None of the flavor Dockerfiles set a non-root USER, so processes run as root. This does not by itself grant host privileges, but it increases impact if container isolation is weakened. Affects both the C++ and Rust development environments. Status: under active review and optimization." + detectability is 4 + detectability_post is 3 + aspect is server-dockerfile-cpp, server-dockerfile-rust + fmea:cause is attack-vector-runtime01 + fmea:effect is impact-runtime01 + fmea:control is mitigation-runtime01 +} + +attack-vector-runtime01 is attack-vector { + description is "Container processes run as root because no non-root user is configured, so a container breakout or malicious mounted content executes with elevated in-container privileges." + occurrence is 3 + occurrence_post is 2 + fmea:mode is threat-runtime01-priv-escape +} + +impact-runtime01 is impact { + description is "Host compromise on a developer workstation or CI runner, enabling malicious code injection, build-artifact tampering, and compromise of signing workflows, providing a direct path into the software supply chain." + severity is 8 + fmea:mode is threat-runtime01-priv-escape +} + +mitigation-runtime01 is mitigation { + custom:status is "Under review" + custom:evidence is "No privileged or added-capability run flags are set in .devcontainer/**/devcontainer.json; a non-root default USER is not yet configured in the Dockerfiles." + description is "Mitigations under review:\n\n- Containers are run without the privileged flag or added capabilities\n- Introduction of a non-root default USER in the flavor images\n- Investigation of least-capability runtime configurations for consumers\n- User namespaces and seccomp/AppArmor profiles evaluation" + fmea:mode is threat-runtime01-priv-escape +} + +planned-mitigation-runtime01-priv-review is planned-mitigation { + description is "Add a non-root default USER to the flavor images and document the minimal set of capabilities consumers should grant at runtime." + fmea:cause is attack-vector-runtime01 +} + +# --- SUPPLY_CHAIN_03: GitHub Actions runner compromise -------------------- + +threat-sc03-runner-compromise is threat { + custom:title is "GitHub Actions Runner Compromise" + custom:threat-id is "SUPPLY_CHAIN_03" + custom:stride is "Tampering" + custom:risk-level is "High" + custom:capec is "CAPEC-187: Malicious Automated Software Update" + custom:cwe is "CWE-346: Origin Validation Error" + description is "Compromise of a GitHub Actions runner during the build process allows injection of malicious code into the container images." + remark is "Compromised GitHub Actions runners could inject malicious code into container images during the build process." + detectability is 4 + detectability_post is 2 + aspect is process-github-actions-build + fmea:cause is attack-vector-sc03 + fmea:effect is impact-sc03 + fmea:control is mitigation-sc03 +} + +attack-vector-sc03 is attack-vector { + description is "A malicious or compromised GitHub Action or runner step executes attacker-controlled code within the build environment." + occurrence is 2 + occurrence_post is 1 + fmea:mode is threat-sc03-runner-compromise +} + +impact-sc03 is impact { + description is "Injection of malicious code into signed, published container images consumed by all downstream users." + severity is 8 + fmea:mode is threat-sc03-runner-compromise +} + +mitigation-sc03 is mitigation { + custom:status is "Implemented" + custom:evidence is "Commit-SHA-pinned actions and step-security/harden-runner across .github/workflows/; least-privilege GITHUB_TOKEN permissions." + description is "Mitigations implemented:\n\n- Step Security harden-runner action for build environment hardening\n- All GitHub Actions pinned to specific commit SHAs\n- Minimal permissions principle implemented\n- Ephemeral, isolated build environments\n- Container image signing and verification with ephemeral keys" + fmea:mode is threat-sc03-runner-compromise +} + +# --- DATA_01: Development secrets exposure --------------------------------- + +threat-data01-secrets is threat { + custom:title is "Development Secrets Exposure" + custom:threat-id is "DATA_01" + custom:stride is "Information Disclosure" + custom:risk-level is "Medium" + custom:capec is "CAPEC-204: Lifting Sensitive Data Embedded in Cache" + custom:cwe is "CWE-312: Cleartext Storage of Sensitive Information" + description is "Accidental inclusion of secrets, API keys, or credentials in container layers or build logs." + remark is "Secrets, API keys, or credentials could be accidentally included in container images or exposed in build logs during the build process." + detectability is 3 + detectability_post is 2 + aspect is process-github-actions-build + fmea:cause is attack-vector-data01 + fmea:effect is impact-data01 + fmea:control is mitigation-data01 +} + +attack-vector-data01 is attack-vector { + description is "A build step writes a secret into an image layer or emits it to the build log." + occurrence is 3 + occurrence_post is 2 + fmea:mode is threat-data01-secrets +} + +impact-data01 is impact { + description is "Unauthorized access to development systems using leaked credentials." + severity is 6 + fmea:mode is threat-data01-secrets +} + +mitigation-data01 is mitigation { + custom:status is "Implemented" + custom:evidence is "Allowlist .dockerignore restricting the build context to .devcontainer/**; targeted build bind-mounts in .devcontainer/**/Dockerfile; GitHub secret scanning and push protection; MegaLinter secret detection (REPOSITORY_GITLEAKS, REPOSITORY_SECRETLINT) in .mega-linter.yml." + description is "Mitigations implemented:\n\n- Allowlist .dockerignore excludes everything except .devcontainer/ from the build context, so no source, credentials, caches, or test artifacts enter an image layer\n- Build steps bind-mount only the specific files they need instead of copying the whole repository into a layer\n- GitHub native secret scanning and push protection enabled on the repository\n- Secret detection in CI via MegaLinter (gitleaks, secretlint)\n- Build-time secrets kept out of image layers and workflow logs" + fmea:mode is threat-data01-secrets +} + +planned-mitigation-data01-narrow-context is planned-mitigation { + description is "Narrow the declared Docker build context root from the repository root to .devcontainer/ (updating devcontainer.json context, initializeCommand, the Dockerfile bind-mount paths, and the build-push workflows) so the context is minimal by construction rather than filtered by .dockerignore." + fmea:cause is attack-vector-data01 +} + +# --- SUPPLY_CHAIN_04: Container registry account takeover ------------------ + +threat-sc04-registry-takeover is threat { + custom:title is "Container Registry Account Takeover" + custom:threat-id is "SUPPLY_CHAIN_04" + custom:stride is "Spoofing" + custom:risk-level is "High" + custom:capec is "CAPEC-151: Identity Spoofing" + custom:cwe is "CWE-287: Improper Authentication" + description is "Compromise of a GitHub account or organization leads to malicious container images being published to the registry." + remark is "Account compromise could allow attackers to publish malicious container images to the GitHub Container Registry." + detectability is 4 + detectability_post is 2 + aspect is datastore-ghcr-registry + fmea:cause is attack-vector-sc04 + fmea:effect is impact-sc04 + fmea:control is mitigation-sc04 +} + +attack-vector-sc04 is attack-vector { + description is "An attacker obtains publish credentials through phishing, credential theft, or a compromised token." + occurrence is 2 + occurrence_post is 1 + fmea:mode is threat-sc04-registry-takeover +} + +impact-sc04 is impact { + description is "Distribution of malicious images under a trusted identity to all consumers of the registry." + severity is 9 + fmea:mode is threat-sc04-registry-takeover +} + +mitigation-sc04 is mitigation { + custom:status is "Implemented" + custom:evidence is "Build-provenance attestations signed via GitHub OIDC (actions/attest, attest-build-provenance) in .github/workflows/wc-build-push.yml; branch and tag protection; OSSF Scorecard workflow." + description is "Mitigations implemented:\n\n- Strong authentication with 2FA/MFA requirements\n- Least privilege access controls and RBAC\n- Container images signed with GitHub artifact attestations using ephemeral OIDC keys\n- Automated vulnerability scanning and detection\n- Registry access logging and monitoring\n- OSSF Scorecard compliance monitoring" + fmea:mode is threat-sc04-registry-takeover +} + +# --- VULN_01: Vulnerable dependencies ------------------------------------- + +threat-vuln01-vuln-deps is threat { + custom:title is "Vulnerable Dependencies" + custom:threat-id is "VULN_01" + custom:stride is "Elevation of Privilege" + custom:risk-level is "Medium" + custom:capec is "CAPEC-549: Local Execution of Code" + custom:cwe is "CWE-1104: Use of Unmaintained Third Party Components" + description is "Use of dependencies with known security vulnerabilities, including the acknowledged CVE-2025-50181 and CVE-2025-50182 in Conan." + remark is "Known vulnerabilities in dependencies could be exploited for code execution or privilege escalation. Some vulnerabilities such as CVE-2025-50181 and CVE-2025-50182 are acknowledged, tracked, and monitored." + detectability is 2 + detectability_post is 2 + aspect is process-dependency-mgmt + fmea:cause is attack-vector-vuln01 + fmea:effect is impact-vuln01 + fmea:control is mitigation-vuln01 +} + +attack-vector-vuln01 is attack-vector { + description is "A known-vulnerable component shipped in the image is exercised by an attacker." + occurrence is 5 + occurrence_post is 3 + fmea:mode is threat-vuln01-vuln-deps +} + +impact-vuln01 is impact { + description is "Code execution or privilege escalation on systems running the affected tooling." + severity is 6 + fmea:mode is threat-vuln01-vuln-deps +} + +mitigation-vuln01 is mitigation { + custom:status is "Implemented" + custom:evidence is "Daily image scanning (Trivy via crazy-max/ghaction-container-scan) with SARIF upload to the Security tab in .github/workflows/vulnerability-scan.yml; .github/dependabot.yml; SBOM attestation via anchore/sbom-action." + description is "Mitigations implemented:\n\n- Automated daily image vulnerability scanning (Trivy via ghaction-container-scan)\n- Dependabot for automated dependency updates\n- Software Bill of Materials (SBOM) attestation generation and maintenance\n- Regular security audits of dependencies\n- Acknowledged CVE tracking with documented mitigation plans\n- SARIF upload to the GitHub Security tab for visibility" + fmea:mode is threat-vuln01-vuln-deps +} + +# --- SUPPLY_CHAIN_05: Malicious VS Code extension ------------------------- + +threat-sc05-malicious-extension is threat { + custom:title is "Malicious VS Code Extension" + custom:threat-id is "SUPPLY_CHAIN_05" + custom:stride is "Tampering" + custom:risk-level is "Medium" + custom:capec is "CAPEC-549: Local Execution of Code" + custom:cwe is "CWE-829: Inclusion of Functionality from Untrusted Source" + description is "A compromised or malicious VS Code extension gains access to the development environment and source code." + remark is "Malicious VS Code extensions could access source code, credentials, or compromise the development environment." + detectability is 4 + detectability_post is 3 + aspect is process-vscode-extensions + fmea:cause is attack-vector-sc05 + fmea:effect is impact-sc05 + fmea:control is mitigation-sc05 +} + +attack-vector-sc05 is attack-vector { + description is "A pinned extension version is republished with malicious code, or an unvetted extension is installed." + occurrence is 3 + occurrence_post is 2 + fmea:mode is threat-sc05-malicious-extension +} + +impact-sc05 is impact { + description is "Disclosure of source code or credentials and compromise of the developer workstation." + severity is 5 + fmea:mode is threat-sc05-malicious-extension +} + +mitigation-sc05 is mitigation { + custom:status is "Implemented" + custom:evidence is "Version-pinned extensions in .devcontainer/**/devcontainer.json under version control." + description is "Mitigations implemented:\n\n- All VS Code extensions pinned to specific versions\n- Extension allow-lists in development environments\n- Regular review of extension permissions and source code\n- Use of only trusted extensions from verified publishers\n- Version control of extension configurations" + fmea:mode is threat-sc05-malicious-extension +} + +# --------------------------------------------------------------------------- +# Additional threats from the supply-chain security review +# --------------------------------------------------------------------------- + +# --- SUPPLY_CHAIN_06: Signature verification bypass ----------------------- + +threat-sc06-sig-bypass is threat { + custom:title is "Signature Verification Bypass" + custom:threat-id is "SUPPLY_CHAIN_06" + custom:stride is "Spoofing" + custom:risk-level is "High" + custom:capec is "CAPEC-473: Signature Spoof" + custom:cwe is "CWE-347: Improper Verification of Cryptographic Signature" + description is "Container images are signed at publication, but a consumer that does not verify the signature can be served an unsigned or improperly signed image. The trust assumption that consumers verify signatures is not currently enforced." + detectability is 5 + detectability_post is 3 + aspect is dataflow-image-consumption, datastore-ghcr-registry + fmea:cause is attack-vector-sc06 + fmea:effect is impact-sc06 + fmea:control is mitigation-sc06 +} + +attack-vector-sc06 is attack-vector { + description is "An attacker publishes or substitutes an unsigned or invalidly signed image and a consumer pulls it without performing attestation verification." + occurrence is 3 + occurrence_post is 2 + fmea:mode is threat-sc06-sig-bypass +} + +impact-sc06 is impact { + description is "A tampered image is trusted and executed on developer and CI systems despite the signing controls, defeating the provenance chain." + severity is 8 + fmea:mode is threat-sc06-sig-bypass +} + +mitigation-sc06 is mitigation { + custom:status is "Partially implemented" + custom:evidence is "Build-provenance attestations signed via GitHub OIDC (actions/attest) in .github/workflows/wc-build-push.yml; consumer verification guidance in README.md ('Verify image signature'); policy enforcement planned." + description is "Mitigations:\n\n- Container images signed with GitHub artifact attestations using ephemeral OIDC keys\n- Documented, copy-pasteable `gh attestation verify` instructions for consumers\n- Verification policy to be enforced in downstream CI and, where applicable, admission control\n- Publication of the expected signer workflow, identity, and issuer used for verification" + fmea:mode is threat-sc06-sig-bypass +} + +planned-mitigation-sc06-enforce-verification is planned-mitigation { + description is "Provide and require a `gh attestation verify` step (expected signer workflow and OIDC issuer) for consumers, and add an admission or verification policy in downstream pipelines." + fmea:cause is attack-vector-sc06 +} + +# --- SUPPLY_CHAIN_07: Build provenance forgery ---------------------------- + +threat-sc07-provenance-forgery is threat { + custom:title is "Build Provenance Forgery" + custom:threat-id is "SUPPLY_CHAIN_07" + custom:stride is "Tampering" + custom:risk-level is "High" + custom:capec is "CAPEC-194: Fake the Source of Data" + custom:cwe is "CWE-345: Insufficient Verification of Data Authenticity" + description is "Forged attestations or manipulated provenance records could make a compromised image appear to have a trustworthy build history, undermining the SBOMs and provenance artifacts the project relies on." + detectability is 4 + detectability_post is 2 + aspect is process-github-actions-build, data-asset-build-artifacts + fmea:cause is attack-vector-sc07 + fmea:effect is impact-sc07 + fmea:control is mitigation-sc07 +} + +attack-vector-sc07 is attack-vector { + description is "An attacker forges in-toto or SLSA attestations, or manipulates provenance records, for example by abusing a compromised signing step." + occurrence is 2 + occurrence_post is 1 + fmea:mode is threat-sc07-provenance-forgery +} + +impact-sc07 is impact { + description is "False trust in a compromised image whose provenance appears valid, allowing tampered artifacts to pass supply-chain checks." + severity is 8 + fmea:mode is threat-sc07-provenance-forgery +} + +mitigation-sc07 is mitigation { + custom:status is "Partially implemented" + custom:evidence is "SLSA build-provenance and SBOM attestations signed via GitHub OIDC (actions/attest, attest-build-provenance, anchore/sbom-action) in .github/workflows/wc-build-push.yml, with an in-pipeline `gh attestation verify` step; verification guidance in README.md." + description is "Mitigations:\n\n- SLSA-style build provenance generated for published images\n- in-toto and SBOM attestations signed with ephemeral OIDC keys\n- Immutable retention of attestations alongside the image digest\n- Consumer-side provenance verification documented and to be enforced" + fmea:mode is threat-sc07-provenance-forgery +} + +planned-mitigation-sc07-verify-provenance is planned-mitigation { + description is "Enforce SLSA provenance verification (trusted builder identity and source repository) in consuming pipelines before an image is promoted." + fmea:cause is attack-vector-sc07 +} + +# --- SUPPLY_CHAIN_08: Build cache poisoning ------------------------------- + +threat-sc08-cache-poisoning is threat { + custom:title is "Build Cache Poisoning" + custom:threat-id is "SUPPLY_CHAIN_08" + custom:stride is "Tampering" + custom:risk-level is "High" + custom:capec is "CAPEC-141: Cache Poisoning" + custom:cwe is "CWE-349: Acceptance of Extraneous Untrusted Data With Trusted Data" + description is "A malicious pull request or a poisoned cache key writes attacker-controlled content into the GitHub Actions cache, which is then reused by a trusted build across a trust boundary." + detectability is 5 + detectability_post is 3 + aspect is datastore-build-cache + fmea:cause is attack-vector-sc08 + fmea:effect is impact-sc08 + fmea:control is mitigation-sc08 +} + +attack-vector-sc08 is attack-vector { + description is "A workflow triggered by an untrusted fork writes a cache entry that a privileged build later restores, or a shared cache key is reused across trust boundaries." + occurrence is 3 + occurrence_post is 2 + fmea:mode is threat-sc08-cache-poisoning +} + +impact-sc08 is impact { + description is "Malicious artifacts injected into an otherwise trusted build, tampering with the resulting container images." + severity is 7 + fmea:mode is threat-sc08-cache-poisoning +} + +mitigation-sc08 is mitigation { + custom:status is "Partially implemented" + custom:evidence is "Scope-limited cache keys per workflow; restriction of cache writes from untrusted fork triggers planned." + description is "Mitigations:\n\n- Trust-boundary-specific, scoped cache keys\n- No restore of caches written by untrusted pull-request triggers\n- Content-addressed, integrity-checked cache entries where supported\n- Regular cache eviction and restricted cache-write permissions" + fmea:mode is threat-sc08-cache-poisoning +} + +planned-mitigation-sc08-restrict-cache is planned-mitigation { + description is "Segregate cache keys by trust boundary and prevent privileged builds from restoring caches populated by untrusted fork workflows." + fmea:cause is attack-vector-sc08 +} + +# --- SUPPLY_CHAIN_09: Compromised tool download --------------------------- + +threat-sc09-tool-download is threat { + custom:title is "Compromised Tool Download" + custom:threat-id is "SUPPLY_CHAIN_09" + custom:stride is "Tampering" + custom:risk-level is "High" + custom:capec is "CAPEC-185: Malicious Software Download" + custom:cwe is "CWE-494: Download of Code Without Integrity Check" + description is "Toolchain binaries fetched from vendor download sites, rather than package registries, could be tampered with in transit or at the source and executed during the build." + detectability is 4 + detectability_post is 2 + aspect is external-entity-vendor-downloads, process-dependency-mgmt + fmea:cause is attack-vector-sc09 + fmea:effect is impact-sc09 + fmea:control is mitigation-sc09 +} + +attack-vector-sc09 is attack-vector { + description is "A vendor download is replaced with a malicious binary, or a download without integrity verification is served over a compromised channel." + occurrence is 3 + occurrence_post is 2 + fmea:mode is threat-sc09-tool-download +} + +impact-sc09 is impact { + description is "Execution of attacker-controlled tooling inside the build, contaminating every derived container image." + severity is 8 + fmea:mode is threat-sc09-tool-download +} + +mitigation-sc09 is mitigation { + custom:status is "Partially implemented" + custom:evidence is "SHA256-pinned binary downloads for most tools in .devcontainer/**/Dockerfile; ccache release verified against a pinned minisign public key in .devcontainer/cpp/Dockerfile; some direct downloads remain unverified (see planned actions)." + description is "Mitigations:\n\n- Most vendor binary downloads pinned to SHA256 checksums (ccache, xwin, ARM GNU toolchain, base image, bats)\n- Publisher signature verification where available, for example ccache via minisign\n- Downloads performed over HTTPS from documented, pinned URLs\n- Some direct downloads (CPM.cmake, include-what-you-use, cargo-binstall and the tools it installs, diffoci) are not yet checksum-verified" + fmea:mode is threat-sc09-tool-download +} + +planned-mitigation-sc09-pin-downloads is planned-mitigation { + description is "Add SHA256 verification for the remaining direct downloads (CPM.cmake, include-what-you-use, cargo-binstall and its installed tools, and diffoci) so every fetched binary is integrity-checked." + fmea:cause is attack-vector-sc09 +} + +# --- AVAIL_01: Dependency or registry outage ------------------------------ + +threat-avail01-availability is threat { + custom:title is "Dependency or Registry Outage" + custom:threat-id is "AVAIL_01" + custom:stride is "Denial of Service" + custom:risk-level is "Medium" + custom:capec is "CAPEC-125: Flooding" + custom:cwe is "CWE-400: Uncontrolled Resource Consumption" + description is "Unavailability of an upstream package source, the container registry, or CI runners prevents the containers from being built or consumed, stalling development and releases." + detectability is 2 + detectability_post is 2 + aspect is process-github-actions-build, external-entity-package-repos + fmea:cause is attack-vector-avail01 + fmea:effect is impact-avail01 + fmea:control is mitigation-avail01 +} + +attack-vector-avail01 is attack-vector { + description is "An upstream registry or download source becomes unavailable or rate-limited, or CI runner capacity is exhausted." + occurrence is 4 + occurrence_post is 3 + fmea:mode is threat-avail01-availability +} + +impact-avail01 is impact { + description is "Builds and image pulls fail, blocking development, testing, and release of the containers." + severity is 5 + fmea:mode is threat-avail01-availability +} + +mitigation-avail01 is mitigation { + custom:status is "Partially implemented" + custom:evidence is "Version-pinned apt packages in .devcontainer/**/apt-requirements*.json; BuildKit cache mounts and GitHub Actions build caching." + description is "Mitigations:\n\n- Explicit version pinning of apt packages reduces reliance on always-current upstreams\n- BuildKit cache mounts and Actions caching limit repeated external fetches\n- Integrity-checked, version-pinned downloads can be re-fetched from documented URLs\n- Vendoring of the most critical dependencies where feasible" + fmea:mode is threat-avail01-availability +} + +# --- AUDIT_01: Release action repudiation --------------------------------- + +threat-audit01-repudiation is threat { + custom:title is "Release Action Repudiation" + custom:threat-id is "AUDIT_01" + custom:stride is "Repudiation" + custom:risk-level is "Medium" + custom:capec is "CAPEC-268: Audit Log Manipulation" + custom:cwe is "CWE-778: Insufficient Logging" + description is "Without strong, immutable traceability of who published an image or approved a release, a maintainer could deny having performed an action, or an unauthorised action could go unattributed." + detectability is 4 + detectability_post is 2 + aspect is datastore-source-repository, process-github-actions-build + fmea:cause is attack-vector-audit01 + fmea:effect is impact-audit01 + fmea:control is mitigation-audit01 +} + +attack-vector-audit01 is attack-vector { + description is "A release or publish action is performed without signed, attributable, tamper-evident records linking it to an authenticated identity." + occurrence is 2 + occurrence_post is 1 + fmea:mode is threat-audit01-repudiation +} + +impact-audit01 is impact { + description is "Loss of accountability for releases, weakening audit readiness and incident response." + severity is 5 + fmea:mode is threat-audit01-repudiation +} + +mitigation-audit01 is mitigation { + custom:status is "Partially implemented" + custom:evidence is "Signed commits and protected releases; OIDC-attributed publish steps; provenance and workflow-log retention." + description is "Mitigations:\n\n- Signed commits and protected branches and tags\n- Release actions attributed to authenticated identities via GitHub OIDC\n- Immutable retention of build provenance and workflow logs\n- Documented release-approval trail" + fmea:mode is threat-audit01-repudiation +} + +# --- TOOL_01: Development tool integrity and qualification ----------------- + +threat-tool01-tool-integrity is threat { + custom:title is "Development Tool Integrity and Qualification" + custom:threat-id is "TOOL_01" + custom:stride is "Tampering" + custom:risk-level is "Medium" + custom:capec is "CAPEC-444: Development Alteration" + custom:cwe is "CWE-1357: Reliance on Insufficiently Trustworthy Component" + description is "Incorrect, tampered, or unqualified compilers, analysers, and build tools in the container could silently produce defective or malicious output, which matters when the devcontainer forms part of the regulated software lifecycle evidence chain." + detectability is 4 + detectability_post is 3 + aspect is server-dockerfile-cpp, server-dockerfile-rust + fmea:cause is attack-vector-tool01 + fmea:effect is impact-tool01 + fmea:control is mitigation-tool01 +} + +attack-vector-tool01 is attack-vector { + description is "A tool is installed at an unintended, tampered, or unqualified version without a recorded, verifiable identity." + occurrence is 2 + occurrence_post is 2 + fmea:mode is threat-tool01-tool-integrity +} + +impact-tool01 is impact { + description is "Defective or malicious build output that undermines confidence in the toolchain used to produce regulated software." + severity is 7 + fmea:mode is threat-tool01-tool-integrity +} + +mitigation-tool01 is mitigation { + custom:status is "Partially implemented" + custom:evidence is "Pinned tool versions with checksums in .devcontainer/**/Dockerfile; SBOM enumerates installed tool versions; tool-qualification notes planned." + description is "Mitigations:\n\n- Tool versions pinned with integrity-checked downloads\n- SBOM enumerates the exact installed tool versions\n- Reproducible builds so the toolset can be re-derived\n- Documented tool-qualification assumptions for lifecycle evidence" + fmea:mode is threat-tool01-tool-integrity +} + +planned-mitigation-tool01-qualification is planned-mitigation { + description is "Document tool-qualification assumptions and record the intended, verified versions of safety-relevant tools as lifecycle evidence." + fmea:cause is attack-vector-tool01 +}