Security architecture and threat model

This document is the authoritative reviewer-facing security model for Copy GitHub Repository. It consolidates protected assets, trust assumptions, threat classes, controls, evidence, and residual risk without replacing the behavioral contract in product-contract.md, the architecture in architecture.md, the quality evidence model in quality-strategy.md, or the installation trust authority in installation-security.md.

SECURITY.md remains the vulnerability-reporting and supported-security-version front door.

Security objectives

The project is designed to:

  • preserve the operator-approved source state rather than silently substituting newer state;
  • prevent accidental overwrite/deletion of existing repositories;
  • preserve repository identity and recovery evidence across replacement failures;
  • avoid shell-string command execution and unnecessary credential exposure;
  • fail closed when required host, identity, state, permission, or verification assumptions are not satisfied;
  • make security-relevant evidence and residual risk auditable without overstating unimplemented controls.

Protected assets

Asset Security concern
Source repository identity and approved content state substitution, TOCTOU drift, unauthorized mutation
Destination/archive repository identity overwrite, identity confusion, loss of recovery path
GitHub CLI authentication material disclosure, unintended reuse, logging
Repository settings/protection state accidental weakening or incorrect restoration
Local temporary workspaces tampering, stale/malformed content, resource failure
Recovery/provenance reports integrity, accidental sensitive-data disclosure
Release ZIP/checksum, SBOM, provenance attestations, and future signing evidence artifact substitution, publication compromise
Development/CI dependencies and workflow definitions supply-chain compromise

Actors and trust assumptions

  • Operator / automation supplies intent, repository names, confirmation, local report destinations, and access through an already authenticated GitHub CLI context.
  • CopyGitHubRepo module is trusted to enforce the product contract, safety checks, execution ordering, verification, and evidence semantics.
  • PowerShell runtime is trusted to load and execute the module and helper scripts.
  • Git, Git LFS, and GitHub CLI are external native prerequisites whose executables and behavior are outside the module’s direct control.
  • GitHub.com is the supported remote platform for v0.1.0. API and Git transport availability, authorization, repository identity, and platform-side mutation are external trust dependencies.
  • GitHub Actions / release environment is trusted for CI and release automation subject to repository permissions, workflow integrity, and configured secrets/environments.
  • PowerShell Gallery and GitHub Releases are distribution services, not runtime dependencies of an installed module.

The project does not assume repository names are immutable identities. GitHub repository IDs/node IDs are used where available for identity-sensitive replacement checks.

Trust boundaries and sensitive-data flow

flowchart LR
    Operator[Operator / automation]
    Module[CopyGitHubRepo]
    GHCLI[GitHub CLI auth context]
    Native[Git / Git LFS / gh]
    GitHub[GitHub.com APIs and Git transport]
    Local[Temporary workspace / reports]
    Release[GitHub Actions / Releases / PSGallery]

    Operator --> Module
    GHCLI --> Native
    Module --> Native
    Native --> GitHub
    Module --> GitHub
    Module --> Local
    Release --> Operator

Credential/data rules:

  • The module uses existing GitHub CLI authentication and does not intentionally collect, display, copy, or persist token values.
  • HTTPS Git operations use GitHub CLI credentials through command-scoped Git configuration; interactive credential prompting is disabled.
  • GitHub secrets, webhook secrets, private deploy-key material, GitHub App credentials, environment secrets, and similar secret-bearing configuration are outside the repository-copy contract.
  • Normal results/recovery evidence may contain repository names, immutable repository IDs, commit/tree SHAs, mode, completed stages, failure stage, and verification/provenance evidence.
  • Tokens, secret values, private keys, and unrelated private repository content must not be written intentionally to console output, reports, diagnostics, or CI artifacts.
  • Diagnostic output is still a security boundary: future logging changes must be reviewed for credential and sensitive-content leakage.

Privileged and destructive operations

Security-sensitive mutations include:

  1. archive/rename of an existing destination or same-name source;
  2. destination/replacement repository creation;
  3. Git content and LFS publication;
  4. repository settings restoration;
  5. repository protection restoration;
  6. release/package publication by maintainer workflows.

Planning, -PlanOnly, and -WhatIf remain non-mutating. Before the first GitHub mutation, the application revalidates the immutable approved source state. Exact replacement confirmation and ShouldProcess boundaries are part of the authorization model; same-name destructive confirmation is not bypassed by ordinary confirmation suppression.

After a post-mutation failure, the product preserves known repositories and recovery evidence. It does not automatically delete repositories or rename archives back.

Threat and failure model

Threat / failure class Primary security effect Current mitigation / behavior
Shell/command injection arbitrary local command execution centralized native-process helpers, discrete argument lists, custom security analyzer rules, engineering prohibition on shell-string evaluation / Invoke-Expression
Stale-state substitution / TOCTOU operator approves one source state but another is copied immutable SourceState, pre-mutation revalidation, workspace revalidation, fail-closed SourceStateChangedSincePlanning
Destination overwrite / destructive confusion loss of existing repository archive-before-replace, exact confirmation, immutable identity checks, distinct replacement identity
Repository-name identity confusion wrong repository accepted after rename/recreate immutable GitHub repository identity continuity where available
Credential leakage token compromise existing GitHub CLI auth context, no intentional token persistence/display, command-scoped credential configuration, analyzer detection for direct emission of secret-bearing variables
Malformed or adversarial remote state unsafe execution or incorrect verification validation/normalization, explicit supported-host boundary, approved-plan evidence, destination read-back verification
Native prerequisite compromise arbitrary behavior below module boundary documented prerequisite/trust boundary; centralized invocation and static boundary enforcement reduce but do not eliminate risk
Network/API interruption or throttling incomplete operation / partial mutation failures surface; preservation/recovery semantics apply; timeout/retry hardening is tracked separately
Local disk/temp resource failure interrupted copy/evidence loss failure is not treated as remote success; recovery guidance applies; disk preflight improvements are tracked separately
Partial mutation archive/destination may exist after failure explicit completed-stage/recovery evidence; no automatic rollback/delete
Settings/protection restoration failure verified content with incomplete configuration content verifies first, settings then protection; failure is reported as a distinct late mutation state
Release artifact substitution user installs unintended bytes SHA-256 integrity comparison plus GitHub build-provenance and SBOM attestations bind release evidence to the versioned ZIP; independent publisher signing remains separate under #80
Dependency/workflow compromise CI/release or development environment compromise exact dependency/action pinning, reviewed development dependency versions, scheduled dependency monitoring, and CodeQL analysis of GitHub Actions workflows; live repository security-setting verification remains #79
Persistent PSGallery trust mutation during dev setup workstation trust posture altered development dependency installer targets PSGallery explicitly without changing repository InstallationPolicy; regression is protected by DevelopmentDependencies.Tests.ps1

Security control and evidence matrix

Status vocabulary:

  • Implemented — enforced in repository code/configuration.
  • Automatically verified — protected by tests/analyzers/workflows.
  • Platform-provided / live verification required — depends on live GitHub/repository configuration and must not be inferred from source alone.
  • Planned / open — tracked work that is not yet a current control.
  • Residual risk — risk that remains after current controls.
Control Purpose Current implementation / authority Evidence Status
Approved immutable source state TOCTOU/substitution defense planning + approved-plan execution + workspace checks ApprovedSourceState.Tests.ps1, StaleStateSafety.Tests.ps1, architecture fitness functions Implemented + automatically verified
Archive-before-replace and identity continuity destructive-operation safety replacement orchestration/product contract replacement/same-name integration tests and E2E harnesses Implemented + automatically verified; live evidence remains release-specific
Distinct replacement identity prevents renamed repository from masquerading as replacement immutable repository ID checks where available same-name/replacement tests Implemented + automatically verified
No automatic rollback/delete preservation and forensic/recovery safety recovery/result contract recovery/risk-failure tests Implemented + automatically verified
Centralized native process invocation command-injection/quoting boundary process helpers using argument lists/no shell evaluation native-command tests + PSScriptAnalyzer/style contracts Implemented + automatically verified
Credential minimization reduce token exposure existing gh auth, command-scoped helper, no intentional token persistence/output security/documentation contracts and implementation review Implemented; not a guarantee against compromised prerequisites
GitHub.com-only host guard prevents unvalidated host semantics explicit fail-closed host checks HostName.Tests.ps1 Implemented + automatically verified
Content-before-settings/protection ordering prevents protection from blocking initial publication and makes late failure explicit application orchestration settings/protection tests Implemented + automatically verified
Release ZIP SHA-256 check integrity/corruption detection stable installer/release contract installation-security and release contract tests Implemented contract; does not independently authenticate publisher
Development dependency version review reduce stale development-tool risk exact pins in build/DevelopmentDependencies.psd1; review record below cross-platform Quality Gate and upstream release/advisory review Implemented + automatically verified for selected pins
Security-focused custom PowerShell SAST rules detect high-signal PowerShell security regressions Measure-CgrSecurity in the repository custom analyzer module PSScriptAnalyzerSecurityRules.Tests.ps1 + normal recursive PSScriptAnalyzer Quality Gate Implemented + automatically verified
CodeQL for GitHub Actions workflow-code static analysis .github/workflows/codeql.yml, language actions, security-extended queries CodeQLWorkflow.Tests.ps1 + successful live CodeQL workflow execution Implemented + automatically verified for GitHub Actions workflows; does not scan PowerShell source
Automated dependency/supply-chain monitoring outdated/vulnerable dependency visibility .github/dependabot.yml, .github/workflows/dependency-monitor.yml, dependency-monitoring.md DevelopmentDependencies.Tests.ps1 + scheduled/manual workflow contract Implemented + automatically verified
Live GitHub security-setting baseline secret scanning, push protection, Dependabot/code scanning settings issue #79 live repository settings Platform-provided / live verification required; currently open
Independent release authenticity/signing publisher/artifact authenticity issue #80 future signature/provenance verification Planned / open
PSGallery trust-policy preservation avoid persistent development-host trust mutation dependency installer does not call Set-PSRepository; exact versions are installed from explicit PSGallery source DevelopmentDependencies.Tests.ps1, cross-platform Quality Gate Implemented + automatically verified
SBOM / provenance evidence component/release assurance build/New-ReleaseSbom.ps1, .github/workflows/release.yml, release-sbom.md ReleaseSbom.Tests.ps1, release workflow contracts, cross-platform Quality Gate #686 Implemented + automatically verified

Release SBOM and provenance evidence

Issue #98 is completed. Stable release automation now generates SPDX 2.3 JSON from the completed deterministic release ZIP rather than from an unrelated mutable source tree. build/New-ReleaseSbom.ps1 records the exact shipped file inventory, SHA-256 file and artifact checksums, package/version identity, source commit, deterministic creation metadata, and the SPDX 2.x package verification code required by that format.

The SBOM package graph represents shipped runtime content only. Runtime PowerShell module dependencies are currently none; PowerShell 7.4+, Git, GitHub CLI, and conditional Git LFS are classified as external prerequisites rather than shipped DEPENDS_ON packages. Pester, PSScriptAnalyzer, GitHub Actions dependencies, GitHub Releases, and PowerShell Gallery are development/CI/distribution concerns and are not represented as installed runtime dependencies.

The stable release workflow publishes the .spdx.json sidecar and uses the immutable-pinned consolidated actions/attest action for both build provenance and SBOM attestation of the same versioned ZIP. Required attestation failures fail the release workflow before publication. See release-sbom.md for retrieval, verification, classification, and reproducibility details.

These controls strengthen artifact provenance and machine-readable software inventory, but they do not replace independent publisher signing. GitHub attestations establish statements about artifact digest, workflow/repository identity, and predicates within GitHub’s attestation model; they do not independently authenticate a separately managed publisher key, prove vulnerability absence, or make semantic SBOM classification infallible. Independent signing remains the distinct #80 control.

Dependency and trust inventory

Class Current dependency / service Security posture
Runtime platform PowerShell 7.4+ external prerequisite
Runtime native prerequisite Git external executable/trust boundary
Runtime native prerequisite GitHub CLI authentication/API prerequisite
Conditional runtime prerequisite Git LFS required for FullHistory and Snapshot with approved LFS content
Runtime PowerShell modules none declared by the module manifest no third-party PowerShell runtime dependency currently shipped
Development modules Pester 6.1.0, PSScriptAnalyzer 1.25.0 exact-version pinned; weekly freshness/advisory monitoring is implemented under #78
CI actions GitHub Actions referenced by workflows immutable SHA pinning is repository policy; Dependabot proposes reviewed updates and CodeQL analyzes workflow code
Runtime remote service GitHub.com v0.1.0 supported host and primary external service
Distribution GitHub Releases, PowerShell Gallery release/distribution trust boundaries; not installed-module runtime dependencies

Development dependency review

The project reviews stable dependency releases before adoption rather than automatically taking every available update:

  • PSScriptAnalyzer 1.25.0 was selected over 1.24.0. It is compatible with the project’s PowerShell 7.4+ baseline and includes analyzer/runtime dependency updates plus additional rules and fixes. The complete repository Quality Gate proved compatibility with this project before #75 was closed.
  • Pester 6.1.0 is the current exact test-framework pin. The project completed the Pester 6 migration and validates the repository test suite against 6.1.0. The matching reviewed-stable baseline is recorded in build/DevelopmentDependencyMonitoring.psd1.
  • The upstream GitHub repository security-advisory APIs are checked for both Pester and PSScriptAnalyzer. This is evidence of the configured advisory review source, not a claim that either project can have no undiscovered vulnerabilities.
  • Exact version pins remain mandatory. Ongoing dependency/supply-chain monitoring is implemented by #78 and documented in dependency-monitoring.md.

Security static-analysis policy

The repository custom PSScriptAnalyzer module adds Measure-CgrSecurity to the normal PSScriptAnalyzerSettings.psd1 path. The rule currently targets high-confidence patterns in production and operational PowerShell:

  • Invoke-Expression / iex dynamic evaluation;
  • explicit cmd /c, sh -c, bash -c, or zsh -c shell interpretation;
  • direct git, gh, or git-lfs invocation from module source that bypasses the centralized native-process boundary;
  • direct output/diagnostic emission of variables whose names indicate token, password, secret, credential, private-key, API-key, or authentication material.

The policy intentionally avoids speculative heuristics that would create routine false positives. A clean analyzer result therefore means the defined patterns were not found; it does not mean arbitrary PowerShell vulnerabilities cannot exist.

Run the policy locally through the canonical project gate:

./build/Test-Project.ps1

For focused contract verification of the security analyzer’s positive detections and safe cases, run:

./build/Test-Project.ps1 -Category Contract

GitHub Actions CodeQL policy

The repository uses .github/workflows/codeql.yml to analyze GitHub Actions workflow code with CodeQL’s actions language and security-extended query suite. The workflow runs when workflow definitions change on main or in pull requests targeting main, on a weekly schedule, and by manual dispatch. Third-party actions are pinned to immutable commit SHAs, checkout does not persist credentials, and the analysis job declares only the permissions required to read repository/action metadata and upload code-scanning results.

The initial CodeQL workflow execution completed successfully. Repository contract tests verify the trigger scope, immutable pins, least-privilege permissions, language selection, query suite, and absence of pull_request_target.

This control is intentionally scoped to GitHub Actions workflow code. It does not analyze the project’s PowerShell source. PowerShell security analysis remains the responsibility of the repository-owned PSScriptAnalyzer policy, Pester tests, review, and other assurance controls. A successful CodeQL run means the configured GitHub Actions analysis completed successfully; it is not proof that all workflow or product vulnerabilities are absent.

Security verification strategy and limits

Current verification combines:

  • Pester Unit/Integration/Contract suites for safety semantics and failure behavior;
  • repository-owned PSScriptAnalyzer policy, including the custom Measure-CgrSecurity rule, plus general PowerShell static analysis;
  • CodeQL analysis of GitHub Actions workflow code;
  • workflow/package/documentation contract testing;
  • controlled E2E harnesses for selected live GitHub behaviors;
  • manual/live verification where platform configuration cannot be proved from repository files.

These mechanisms are not comprehensive SAST. PowerShell source is not covered by a CodeQL language analysis in this project; GitHub Actions workflow code is covered separately by CodeQL. A passing Quality Gate and CodeQL run are strong conformance evidence for the checks that exist; they are not proof that the software is vulnerability-free.

E2E-capable also does not mean a specific release candidate was live-validated. Exact-release-candidate evidence is governed by quality-strategy.md and the release-readiness process.

Privacy and telemetry posture

The project does not define a telemetry/analytics subsystem. It operates on operator-selected GitHub repositories and local paths using the operator’s authenticated GitHub context. It does not intentionally transmit usage analytics to the project maintainer.

Repository content necessarily crosses Git/GitHub transport boundaries as part of the requested copy operation. Local reports/recovery artifacts remain operator-controlled files. Future telemetry, crash reporting, or centralized diagnostics would be a material product/security/privacy change and would require explicit design and documentation rather than being added implicitly.

Residual risk and open hardening

For v0.1.0 review, the following must remain explicit until resolved or accepted by release readiness:

  • #75 — completed: PSScriptAnalyzer 1.25.0 and Pester 6.1.0 are the current exact development pins after dependency review and validation.
  • #76 — completed: focused AST-based security analyzer rules are loaded by the normal PSScriptAnalyzer path and protected by positive/safe contract tests.
  • #77 — completed: CodeQL analyzes GitHub Actions workflow code with immutable action pins, least-privilege permissions, contract coverage, and a successful initial live scan; PowerShell remains outside CodeQL language coverage.
  • #78 — completed: Dependabot monitors GitHub Actions updates and a separate scheduled/manual workflow monitors PowerShell development dependency freshness and upstream published advisories.
  • #79 — live repository security settings have not yet been closed as verified.
  • #80 — independent release authenticity/signing is open; same-channel SHA-256 and GitHub attestations remain distinct from independent publisher authentication.
  • #81 — completed: development dependency installation no longer changes PSGallery trust policy; regression coverage prevents reintroduction of Set-PSRepository/InstallationPolicy mutation.
  • #98 — completed: stable release packaging generates deterministic SPDX 2.3 JSON from the exact release ZIP, publishes it as release evidence, and requires GitHub build-provenance and SBOM attestations; this does not replace independent publisher signing.
  • Native prerequisite compromise (PowerShell/Git/Git LFS/GitHub CLI) remains outside the module’s direct enforcement boundary.
  • GitHub.com availability, authorization, API behavior, and remote-side consistency are external dependencies.
  • Resource exhaustion, timeout, retry, throttling, and interruption hardening tracked under the non-functional follow-up work remains relevant to availability and partial-mutation risk.

Open security work is not automatically a release blocker merely because it is open; #104 must classify blocker versus accepted limitation using evidence and explicit decision authority.

Reporting and incident response

Suspected vulnerabilities should follow SECURITY.md, not public issue disclosure. Serious post-publication security, credential, supply-chain, artifact, or distribution incidents will use the process introduced by #108 once implemented.

Until then, preservation principles still apply: retain exact affected version/commit/artifact identities and relevant non-secret evidence; do not silently overwrite immutable release evidence or destroy repository recovery state.