Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions .github/agents/backend-reviewer.agent.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
---
name: backend-reviewer
description: Go backend review — correctness, concurrency safety, error handling, API contracts, reliability.
tools: [read, search]
---

You are a senior Go reviewer focused on correctness and reliability under load. For each issue cite `file:line` and propose the fix.

Check:

- **Error handling** — every error checked and wrapped with context (`fmt.Errorf("...: %w", err)`); none swallowed or logged-and-continued where it shouldn't be. No `panic` in library/request paths.
- **Concurrency** — data races (would it pass `go test -race`?), unguarded shared state, maps written concurrently, goroutines that can leak or block forever. Mutex scope correct.
- **Context** — `context.Context` plumbed through and its cancellation/deadline honoured on I/O and long operations.
- **Resources** — every `Open`/acquire has a matching `defer Close()`/release; no leaked connections, files, or rows.
- **API contracts** — request/response shapes, status codes, and pagination consistent; backward-compatible changes; input validated at the boundary.
- **Data layer** — queries parameterized; transactions scoped correctly; N+1 and obvious hot-path inefficiencies.
- **Tests** — table-driven where it fits; they exercise error and edge paths, not just the happy path.

Prefer fewer, high-confidence findings. Flag over-engineering and dead code. Leave security-specific deep-dives to `security-reviewer` but call out anything obviously unsafe.
19 changes: 19 additions & 0 deletions .github/agents/frontend-reviewer.agent.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
---
name: frontend-reviewer
description: TypeScript / Next.js review — server-client boundaries, XSS, accessibility, performance, brand consistency.
tools: [read, search]
---

You are a senior frontend reviewer for a Next.js (App Router) + TypeScript codebase. For each issue cite `file:line` and propose the fix.

Check:

- **Server/client boundaries** — `"use client"` only where needed; no server secrets imported into client components; data fetching on the server where it should be; hydration mismatches avoided.
- **XSS / injection** — no `dangerouslySetInnerHTML` without sanitization; URLs and user content escaped; no `eval`-like patterns.
- **Type safety** — no `any` smuggling past the type system; discriminated unions for state; exhaustive handling.
- **Accessibility** — semantic elements, labels on inputs, keyboard focus, alt text, color-contrast intent.
- **Performance** — unnecessary re-renders (stable keys, memo where it matters, no inline object/array props in hot lists); avoid large client bundles; image/font handling.
- **Brand/design consistency** — reuse the real design tokens and components (the V mark, brand colors `#1456F0`/`#EA5EC1`, Geist type). **Never invent a logo, color, or font** — flag any fabricated brand asset.
- **Tests** — components/logic covered; user-facing behavior asserted, not implementation details.

Prefer fewer, high-confidence findings. Flag dead code and over-abstraction.
20 changes: 20 additions & 0 deletions .github/agents/security-reviewer.agent.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
---
name: security-reviewer
description: Adversarial application-security review — OWASP, multi-tenant isolation, BYOK secrets, injection, crypto.
tools: [read, search]
---

You are a skeptical application-security reviewer. Your job is to find the vulnerability, not to be agreeable. Default to **"this is a finding"** when you are unsure, and say why. For every issue: cite `file:line`, name the vulnerability class **with its OWASP/CWE id**, describe the exploit, and propose the fix.

**Review against industry standards.** Map every finding to **OWASP Top 10 (2021)** and the **CWE Top 25** where it fits — e.g. A01 Broken Access Control (CWE-862/639), A02 Cryptographic Failures (CWE-327), A03 Injection (CWE-89/78/79), A04 Insecure Design, A05 Security Misconfiguration, A07 Identification & Auth Failures (CWE-287), A08 Software & Data Integrity (CWE-502 unsafe deserialization), A09 Logging Failures (e.g. secrets in logs), A10 SSRF (CWE-918). Naming the standard makes the finding actionable and auditable.

Hunt specifically for:

- **Broken authorization / multi-tenant data leakage** — any store, query, or API path that isn't scoped to the caller's org/tenant; cross-tenant read or write; missing ownership checks. This is the top risk in `vectorless-control-plane`. Trace the auth context from request to data access.
- **Secrets / BYOK handling** — model keys must be encrypted at rest (AES-256-GCM), never logged, never returned in API responses or error messages; no secrets in client bundles or committed files.
- **Injection** — SQL/command/template injection; always parameterize. **SSRF** on any URL/host taken from input. Unsafe deserialization.
- **Crypto** — weak algorithms, hardcoded keys/IVs, missing authentication on encryption, predictable randomness for security purposes.
- **AuthN** — token validation, session handling, missing rate limits on auth endpoints.
- **Dependencies** — newly added packages with known CVEs or low reputation (supply-chain risk).

Rank findings by severity (critical/high/medium/low). If you find nothing, say what you checked so the absence is meaningful. Do not comment on style or formatting — that is another reviewer's job.
17 changes: 17 additions & 0 deletions .github/agents/test-reliability-reviewer.agent.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
---
name: test-reliability-reviewer
description: Tests & reliability review — do the tests prove behavior, cover edges, and stay deterministic.
tools: [read, search]
---

You review whether a change is actually *proven* and *reliable* — not just whether it compiles. For each issue cite `file:line`.

Check:

- **Do the tests prove the behavior?** A test that passes without exercising the new logic is worthless. Would the test **fail** if the feature were broken? If not, say so.
- **Coverage gaps** — error paths, empty/nil/boundary inputs, concurrency, the specific scenario the issue describes. New behavior with no test is a finding.
- **Determinism / flakiness** — no reliance on wall-clock time, random without a seed, network, sleep-based timing, or ordering of maps/sets. Flag anything that could fail intermittently in CI.
- **Reliability of the change itself** — timeouts and retries on I/O, graceful degradation, idempotency where it matters, resource cleanup on the error path.
- **Test quality** — assertions on outcomes (not internals), clear arrange/act/assert, table-driven where it fits, no over-mocking that hides real behavior.

If the change has adequate tests, say what they cover so it's credible. Recommend the specific missing test cases by name.
22 changes: 22 additions & 0 deletions .github/copilot-instructions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# Copilot review — baseline

You are reviewing a pull request for the Vectorless codebase. Review against the **issue's acceptance criteria** (linked via `Closes HAL-<n>`); flag scope creep. Be concrete: cite `file:line`, explain the risk, propose the fix. Prefer fewer, high-confidence findings over noise.

Review in this order, stop-and-flag if a level fails:

Comment on lines +5 to +6

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Continue through all review levels after a failure.

Line 5 instructs reviewers to stop after the first failed level. The repository standard requires scope, correctness, and security checks in sequence. Stopping at a scope failure can hide an independent security finding. Replace “stop-and-flag” with “flag, then continue through the remaining levels.”

As per coding guidelines, reviewers must flag failures at each level before proceeding to the next level.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/copilot-instructions.md around lines 5 - 6, Update the “Review in
this order” guidance in the review-level instructions to flag any failed level
and then continue through all remaining levels, preserving the sequential scope,
correctness, and security checks.

Source: Coding guidelines

**1. Right thing** — Does the change do exactly what the issue asked, nothing more? Any unrelated edits, dead code, or commented-out blocks?

**2. Done right**
- Correctness & edge cases; nil/undefined and empty-input handling.
- Errors: wrapped with context, never swallowed; `context.Context` cancellation honoured (Go).
- Tests actually **prove** the new behavior (not just exist) and cover error/edge paths.
- Simplicity: is there a smaller solution? No premature abstraction.

**3. Safe (security-first)**
- **Authorization & multi-tenant isolation** — every store/query access scoped to the caller's tenant; no cross-tenant read/write. Highest priority in `vectorless-control-plane`.
- **Secrets / BYOK** — model keys encrypted at rest, never logged or echoed in responses.
- Injection (SQL/command), SSRF, unsafe deserialization, weak/missing crypto.
- New dependencies: justified, reputable, no known CVEs.
- Concurrency (Go): data races, unguarded shared state, leaked goroutines.

For deeper, area-specific review, the specialized agents in `.github/agents/` and the path-scoped rubrics in `.github/instructions/` apply automatically. When in doubt on a security question, **treat it as a finding** and say so explicitly.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail
rg -n -C 3 'agents/|review-prompt|copilot-instructions|instructions/' AGENTS.md .github

Repository: hallelx2/vectorless

Length of output: 2797


🏁 Script executed:

#!/bin/bash
set -euo pipefail
printf '--- AGENTS.md lines 1-35 ---\n'
sed -n '1,35p' AGENTS.md
printf '\n--- .github/copilot-instructions.md lines 1-30 ---\n'
sed -n '1,30p' .github/copilot-instructions.md
printf '\n--- .github/workflows/jules-review.yml lines 1-55 ---\n'
sed -n '1,55p' .github/workflows/jules-review.yml
printf '\n--- agent instruction files ---\n'
fd -a '\.agent\.md$|\.md$' .github/agents .github/instructions 2>/dev/null | sort

Repository: hallelx2/vectorless

Length of output: 248


🏁 Script executed:

#!/bin/bash
set -euo pipefail
printf '%s\n' '--- AGENTS.md lines 1-35 ---'
sed -n '1,35p' AGENTS.md
printf '%s\n' ''
printf '%s\n' '--- .github/copilot-instructions.md lines 1-30 ---'
sed -n '1,30p' .github/copilot-instructions.md
printf '%s\n' ''
printf '%s\n' '--- .github/workflows/jules-review.yml lines 1-55 ---'
sed -n '1,55p' .github/workflows/jules-review.yml
printf '%s\n' ''
printf '%s\n' '--- agent/rubric instruction files ---'
git ls-files '.github/agents/*' '.github/instructions/*' 2>/dev/null | sort

Repository: hallelx2/vectorless

Length of output: 6648


Do not say specialized agents apply automatically.

Line 22 makes every specialized agent sound automatic. AGENTS.md says to tag specialized reviewers for a deep pass, and the Jules workflow feeds .github/agents/security-reviewer.agent.md through review-prompt. Reword this to say path-scoped rubrics in .github/instructions/ apply automatically, while specialized agents need explicit selection or workflow invocation.

🧰 Tools
🪛 LanguageTool

[uncategorized] ~22-~22: The official name of this software platform is spelled with a capital “H”.
Context: ...cific review, the specialized agents in .github/agents/ and the path-scoped rubrics in...

(GITHUB)


[uncategorized] ~22-~22: The official name of this software platform is spelled with a capital “H”.
Context: ...agents/and the path-scoped rubrics in.github/instructions/` apply automatically. Whe...

(GITHUB)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/copilot-instructions.md at line 22, Update the guidance around
path-scoped review in the instructions text: state that rubrics in
`.github/instructions/` apply automatically, but specialized agents in
`.github/agents/` require explicit selection or workflow invocation. Remove the
implication that specialized agents apply automatically, while preserving the
existing security-review guidance.

24 changes: 24 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Dependency CVE automation. Dependabot opens PRs for vulnerable/outdated deps.
# Ecosystems with no manifest in a given repo are simply skipped.
# Also enable per repo: Settings → Code security → Dependabot alerts + security updates.
version: 2
updates:
- package-ecosystem: github-actions
directory: "/"
schedule:
interval: weekly
labels: [dependencies, security]

Check warning

Code scanning / Semgrep OSS

Semgrep Finding: package_managers.dependabot.dependabot-missing-cooldown.dependabot-missing-cooldown Warning

This Dependabot configuration does not set a cooldown period. Newly published packages can be malicious or unstable. Add a cooldown block with default-days: 7 to each package-ecosystem entry under updates to wait 7 days before proposing updates to newly published package versions. Reference: https://docs.github.com/en/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file#cooldown
Comment on lines +6 to +10
Comment on lines +6 to +10

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔒 Security & Privacy | 🟠 Major

Add a seven-day cooldown to every Dependabot update block.

All three update blocks omit cooldown.default-days. Add:

cooldown:
  default-days: 7
  • .github/dependabot.yml#L6-L10: add the cooldown to the github-actions block.
  • .github/dependabot.yml#L12-L17: add the cooldown to the gomod block.
  • .github/dependabot.yml#L19-L24: add the cooldown to the npm block.

As per coding guidelines, dependency risk is part of the required security review.

🧰 Tools
🪛 GitHub Check: Semgrep OSS

[warning] 6-10: Semgrep Finding: package_managers.dependabot.dependabot-missing-cooldown.dependabot-missing-cooldown
This Dependabot configuration does not set a cooldown period. Newly published packages can be malicious or unstable. Add a cooldown block with default-days: 7 to each package-ecosystem entry under updates to wait 7 days before proposing updates to newly published package versions. Reference: https://docs.github.com/en/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file#cooldown

📍 Affects 1 file
  • .github/dependabot.yml#L6-L10 (this comment)
  • .github/dependabot.yml#L12-L17
  • .github/dependabot.yml#L19-L24
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/dependabot.yml around lines 6 - 10, Add a cooldown configuration
with default-days set to 7 to each Dependabot update block: the github-actions
block at .github/dependabot.yml lines 6-10, the gomod block at lines 12-17, and
the npm block at lines 19-24.

Sources: Coding guidelines, Linters/SAST tools


- package-ecosystem: gomod
directory: "/"
schedule:
interval: weekly
open-pull-requests-limit: 5
labels: [dependencies, security]

Check warning

Code scanning / Semgrep OSS

Semgrep Finding: package_managers.dependabot.dependabot-missing-cooldown.dependabot-missing-cooldown Warning

This Dependabot configuration does not set a cooldown period. Newly published packages can be malicious or unstable. Add a cooldown block with default-days: 7 to each package-ecosystem entry under updates to wait 7 days before proposing updates to newly published package versions. Reference: https://docs.github.com/en/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file#cooldown
Comment on lines +12 to +17

- package-ecosystem: npm
directory: "/"
schedule:
interval: weekly
open-pull-requests-limit: 5
labels: [dependencies, security]

Check warning

Code scanning / Semgrep OSS

Semgrep Finding: package_managers.dependabot.dependabot-missing-cooldown.dependabot-missing-cooldown Warning

This Dependabot configuration does not set a cooldown period. Newly published packages can be malicious or unstable. Add a cooldown block with default-days: 7 to each package-ecosystem entry under updates to wait 7 days before proposing updates to newly published package versions. Reference: https://docs.github.com/en/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file#cooldown
Comment on lines +19 to +24
12 changes: 12 additions & 0 deletions .github/instructions/backend.instructions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
---
applyTo: "**/*.go"
---

Go backend review for this file. Cite `file:line` + the fix.

- Errors checked and wrapped with context (`%w`); none swallowed; no `panic` in library/request paths.
- Concurrency: no data races (must pass `go test -race`), shared state guarded, no leaked/blocked goroutines.
- `context.Context` plumbed through; cancellation/deadlines honoured on I/O.
- Resources: every acquire has a matching `defer` release; no leaked connections/rows/files.
- Queries parameterized; input validated at the boundary; transactions scoped correctly.
- Tests exercise error and edge paths, not just the happy path. Flag dead code and over-engineering.
12 changes: 12 additions & 0 deletions .github/instructions/frontend.instructions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
---
applyTo: "**/*.ts,**/*.tsx,**/*.css"
---

TypeScript / Next.js review for this file. Cite `file:line` + the fix.

- Server/client boundaries correct; no server secrets in client components; no hydration mismatches.
- No `dangerouslySetInnerHTML` without sanitization; user content/URLs escaped.
- No `any` smuggled past the types; exhaustive handling of unions.
- Accessibility: semantic elements, input labels, keyboard focus, alt text.
- Performance: avoid needless re-renders (stable keys, no inline object props in hot lists); watch bundle size.
- Brand consistency: reuse real design tokens/components (V mark, `#1456F0`/`#EA5EC1`, Geist). Never invent a logo/color/font.
11 changes: 11 additions & 0 deletions .github/instructions/security.instructions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
---
applyTo: "**"
---

Security review for every changed file, against **OWASP Top 10 (2021)** + **CWE Top 25**. Treat an uncertain security question as a finding and say so. Cite `file:line`, the **OWASP/CWE id**, and the fix.

- **Authorization & multi-tenant isolation** — is every data access scoped to the caller's org/tenant? Any cross-tenant read/write, missing ownership check, or auth context that isn't threaded to the query? (Top risk in `vectorless-control-plane`.)
- **Secrets / BYOK** — model keys encrypted at rest, never logged, never returned in responses/errors; no secrets in client bundles or committed files.
- **Injection / SSRF** — parameterize queries; validate and allowlist any URL/host from input; no unsafe deserialization.
- **Crypto** — strong algorithms, no hardcoded keys/IVs, authenticated encryption, secure randomness.
- **Dependencies** — new packages justified, reputable, no known CVEs.
40 changes: 40 additions & 0 deletions .github/workflows/jules-review.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
name: jules-review

# Optional: auto-invoke Jules for a security-focused review on every PR.
# PRIMARY path is simply commenting "@jules review this PR for security" on a PR —
# Jules reads AGENTS.md + .github/agents/security-reviewer.agent.md and responds.
# This workflow automates that, but only runs when a JULES_API_KEY secret is present,
# so it no-ops safely in repos that haven't set one.

on:
pull_request:
types: [opened, synchronize, ready_for_review]

permissions:
contents: read
pull-requests: write

jobs:
jules:
runs-on: ubuntu-latest
steps:
- name: Guard — only run when a Jules key is configured
id: guard
run: |
if [ -n "${{ secrets.JULES_API_KEY }}" ]; then
echo "enabled=true" >> "$GITHUB_OUTPUT"
else
echo "enabled=false" >> "$GITHUB_OUTPUT"
echo "No JULES_API_KEY set — skipping automated Jules review. Use @jules on the PR instead."
fi
Comment on lines +21 to +29
Comment on lines +21 to +29

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== workflow excerpt =="
sed -n '1,80p' .github/workflows/jules-review.yml 2>/dev/null || true

echo
echo "== all interpolations of JULES_API_KEY in workflows =="
rg -n '\$\{\{\s*secrets\.JULES_API_KEY\s*\}\}' .github/workflows || true

echo
echo "== surrounding workflow context =="
cat -n .github/workflows/jules-review.yml | sed -n '1,80p'

Repository: hallelx2/vectorless

Length of output: 4045


🌐 Web query:

GitHub Actions secrets injected as environment variables command injection run step interpolate expressions avoid using untrusted expressions

💡 Result:

In GitHub Actions, using the ${{ }} expression syntax directly within run steps creates a significant security risk known as command injection [1][2][3]. This occurs because GitHub processes these expressions via macro-expansion before the shell interprets the script, effectively injecting the value directly into your command string [1][4][3]. If the value contains malicious input—such as an attacker-controlled issue title or branch name—the injected code will execute with the permissions of the runner [2][5][3]. To prevent this, you should never interpolate untrusted expressions directly into shell commands [4]. Instead, use the following best practices: 1. Use intermediate environment variables: Set the untrusted input to an environment variable in the env block of the step [1][6][7]. This ensures the value is stored in memory rather than being interpolated into the script during generation [1][8][9]. Example (Secure): env: UNTRUSTED_INPUT: ${{ github.event.issue.title }} run: | echo "$UNTRUSTED_INPUT" 2. Reference variables using native shell syntax: Once the input is assigned to an environment variable, access it using standard shell syntax (e.g., "$UNTRUSTED_INPUT") rather than GitHub's expression syntax [6][7][3]. Using the ${{ env.VAR }} syntax inside the run block will re-introduce the vulnerability by expanding the value during script generation [6]. 3. Quote variables: Always wrap shell variables in double quotes to prevent word splitting and other common shell injection issues [1][8][7]. 4. Follow the principle of least privilege: Even when using environment variables, the input remains untrusted [2][3]. Reduce the risk by limiting the permissions of the GITHUB_TOKEN for your workflows and using code scanning to detect potential injection vulnerabilities automatically [2][6][3]. By treating all external input as untrusted and relying on environment variables to pass data safely into your scripts, you can significantly mitigate the risk of command injection [1][2][5].

Citations:


Do not interpolate JULES_API_KEY into the workflow script.

${{ secrets.JULES_API_KEY }} is expanded before the shell parses the step, so a secret containing quotes, command substitution, or a newline can alter the commands. Pass the secret through env and test "$JULES_API_KEY".

Proposed fix
       - name: Guard — only run when a Jules key is configured
         id: guard
+        env:
+          JULES_API_KEY: ${{ secrets.JULES_API_KEY }}
         run: |
-          if [ -n "${{ secrets.JULES_API_KEY }}" ]; then
+          if [ -n "$JULES_API_KEY" ]; then
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
- name: Guard — only run when a Jules key is configured
id: guard
run: |
if [ -n "${{ secrets.JULES_API_KEY }}" ]; then
echo "enabled=true" >> "$GITHUB_OUTPUT"
else
echo "enabled=false" >> "$GITHUB_OUTPUT"
echo "No JULES_API_KEY set — skipping automated Jules review. Use @jules on the PR instead."
fi
- name: Guard — only run when a Jules key is configured
id: guard
env:
JULES_API_KEY: ${{ secrets.JULES_API_KEY }}
run: |
if [ -n "$JULES_API_KEY" ]; then
echo "enabled=true" >> "$GITHUB_OUTPUT"
else
echo "enabled=false" >> "$GITHUB_OUTPUT"
echo "No JULES_API_KEY set — skipping automated Jules review. Use `@jules` on the PR instead."
fi
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/jules-review.yml around lines 21 - 29, Update the guard
step identified by id "guard" so the secret is passed through the step’s env
configuration rather than interpolated in the shell script. Test the quoted
"$JULES_API_KEY" environment variable for non-empty content while preserving the
existing enabled output and skip message behavior.

Source: Coding guidelines

- name: Jules security review
if: steps.guard.outputs.enabled == 'true'
uses: sanjay3290/jules-pr-reviewer@f364d6653b2e9dc5a24df3ef12974aa264148c98 # v1.0.1
with:
jules-api-key: ${{ secrets.JULES_API_KEY }}
github-token: ${{ github.token }}
review-prompt: >
Review this pull request as an adversarial application-security reviewer.
Follow .github/agents/security-reviewer.agent.md: hunt for broken authorization
and multi-tenant data leakage, BYOK secret handling, injection/SSRF, and weak
crypto. Default to "this is a finding" when unsure. Cite file:line and propose the fix.
139 changes: 139 additions & 0 deletions .github/workflows/security.reusable.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
name: security (reusable)

# Deterministic security scanners, written once and called by every repo via
# `.github/workflows/security.yml`. The AI reviewers (Copilot agents + Jules) sit
# on top of this. This layer catches the textbook vuln classes + real CVEs.
# Layers: secrets, dependency CVEs (multi-ecosystem + Go-specific), SAST against
# OWASP Top 10 / CWE Top 25, and infra/misconfig.

on:
workflow_call: {}

permissions:
contents: read
pull-requests: read
security-events: write
Comment on lines +12 to +15

jobs:
secret-scan:
name: Secrets (gitleaks)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

Check warning

Code scanning / Semgrep OSS

Semgrep Finding: yaml.github-actions.security.github-actions-mutable-action-tag.github-actions-mutable-action-tag Warning

GitHub Actions step uses a mutable tag or branch reference. Tags and branch names can be silently repointed by the action owner, enabling supply-chain attacks — as seen in the trivy-action and kics-github-action compromises. Pin the reference to a full 40-character commit SHA instead, e.g. uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608.
with:
fetch-depth: 0
Comment on lines +22 to +24

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== file sizes =="
wc -l .github/workflows/security.reusable.yml 2>/dev/null || true

echo "== relevant workflow section =="
sed -n '1,160p' .github/workflows/security.reusable.yml 2>/dev/null || true

echo "== checkout occurrences with nearby lines =="
nl -ba .github/workflows/security.reusable.yml 2>/dev/null | sed -n '1,160p' | awk '/uses: actions\/checkout/{start=NR-4; end=NR+6; for(i=start;i<=end;i++) if(a[i]) print a[i]; delete a} {a[NR]=$0}'

Repository: hallelx2/vectorless

Length of output: 5145


🌐 Web query:

actions/checkout v4 persist-credentials default true README

💡 Result:

In actions/checkout v4, the default value for the persist-credentials input is true [1][2][3]. When persist-credentials is set to true (the default), the action persists the authentication token or SSH key in the local git configuration [1][4]. This allows subsequent steps in your workflow to run authenticated git commands (e.g., git push) without needing to manually configure credentials [1][5]. The token is automatically removed during the post-job cleanup phase [1][4]. If you do not require these permissions for subsequent steps, you can set persist-credentials to false to opt-out and enhance your workflow security [1][5].

Citations:


Disable credential persistence in every scanner checkout.

actions/checkout@v4 persists the workflow token in .git/config by default. Set persist-credentials: false on these seven checkout steps because the scanners only need the worktree.

🧰 Tools
🪛 GitHub Check: Semgrep OSS

[warning] 22-22: Semgrep Finding: yaml.github-actions.security.github-actions-mutable-action-tag.github-actions-mutable-action-tag
GitHub Actions step uses a mutable tag or branch reference. Tags and branch names can be silently repointed by the action owner, enabling supply-chain attacks — as seen in the trivy-action and kics-github-action compromises. Pin the reference to a full 40-character commit SHA instead, e.g. uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608.

🪛 zizmor (1.28.0)

[warning] 22-24: credential persistence through GitHub Actions artifacts (artipacked): does not set persist-credentials: false

(artipacked)

📍 Affects 1 file
  • .github/workflows/security.reusable.yml#L22-L24 (this comment)
  • .github/workflows/security.reusable.yml#L35-L35
  • .github/workflows/security.reusable.yml#L58-L58
  • .github/workflows/security.reusable.yml#L77-L77
  • .github/workflows/security.reusable.yml#L92-L92
  • .github/workflows/security.reusable.yml#L111-L111
  • .github/workflows/security.reusable.yml#L131-L131
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/security.reusable.yml around lines 22 - 24, Disable
credential persistence for every actions/checkout@v4 step in
.github/workflows/security.reusable.yml at lines 22-24, 35, 58, 77, 92, 111, and
131 by setting persist-credentials to false alongside the existing checkout
options.

Source: Linters/SAST tools

- uses: gitleaks/gitleaks-action@v2

Check warning

Code scanning / Semgrep OSS

Semgrep Finding: yaml.github-actions.security.github-actions-mutable-action-tag.github-actions-mutable-action-tag Warning

GitHub Actions step uses a mutable tag or branch reference. Tags and branch names can be silently repointed by the action owner, enabling supply-chain attacks — as seen in the trivy-action and kics-github-action compromises. Pin the reference to a full 40-character commit SHA instead, e.g. uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608.
env:
GITHUB_TOKEN: ${{ github.token }}

sast-semgrep:
name: SAST — OWASP Top 10 + CWE Top 25 (Semgrep)
runs-on: ubuntu-latest
container:
image: semgrep/semgrep

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf 'Repository files matching security workflows:\n'
git ls-files | rg '(^|/)(security.*\.yml|security.*\.yaml)$|\.github/workflows/' || true

printf '\nWorkflow snippets:\n'
for f in .github/workflows/security.yml .github/workflows/security.reusable.yml; do
  if [ -f "$f" ]; then
    echo "--- $f"
    nl -ba "$f" | sed -n '1,220p'
  fi
done

printf '\nDigest/tag-related patterns in workflows:\n'
rg -n '@|container:\s*image:|git://|sha256:|digest' .github/workflows 2>/dev/null || true

Repository: hallelx2/vectorless

Length of output: 467


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '--- .github/workflows/security.yml\n'
awk '{printf "%6d  %s\n", NR, $0}' .github/workflows/security.yml

printf '\n--- .github/workflows/security.reusable.yml\n'
awk '{printf "%6d  %s\n", NR, $0}' .github/workflows/security.reusable.yml

printf '\n--- Digest/tag-related patterns in workflows\n'
rg -n '@|container:\s*image:|git://|sha256:|digest' .github/workflows 2>/dev/null || true

python3 - <<'PY'
from urllib.request import urlopen, Request
import json

repo = 'semgrep/semgrep'
tag = 'latest'  # default used when no digest/tag is supplied
ref = f'https://api.github.com/repos/{repo}/git/ref/tags/{tag}'
req = Request(ref, headers={'Accept': 'application/vnd.github+json', 'User-Agent': 'CodeRabbit-verifier'})
try:
    with urlopen(req, timeout=15) as r:
        data = json.loads(r.read())
    print(f'TAG_REF={ref}')
    print('object_type', data.get('object', {}).get('type'))
    print('tag-object_sha', data.get('object', {}).get('sha'))
except Exception as e:
    print('GITHUB_REF_QUERY_ERROR', repr(e))
PY

python3 - <<'PY'
from urllib.request import urlopen, Request
import json

repo = 'semgrep/semgrep'
image = 'docker-registry.redhat.io/openshift/release/semgrep'
tag = 'latest'

urls = [
    f'https://api.github.com/repos/{repo}/releases/tags/{tag}',
    f'https://hub.docker.com/v2/repositories/{repo}/tags/{tag}',
]
for url in urls:
    req = Request(url, headers={'Accept': 'application/vnd.github+json,application/json;data=json;profiles=meta,vnd.docker.distribution.manifest.v2+json', 'User-Agent': 'CodeRabbit-verifier'})
    try:
        with urlopen(req, timeout=15) as r:
            body = r.read(2048)
        print(f'URL={url}')
        print('status', r.status)
        print('url', url)
        print('last_modified', r.headers.get('last-modified'))
        print('content_type', r.headers.get('content-type'))
        print('body:', body.decode('utf-8', 'replace')[:2000])
    except Exception as e:
        print(f'URL={url} ERROR={repr(e)}')
PY

Repository: hallelx2/vectorless

Length of output: 248


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '%s\n' '--- .github/workflows/security.yml'
awk '{printf "%6d  %s", NR, $0; print ""}' .github/workflows/security.yml

printf '%s\n' ''
printf '%s\n' '--- .github/workflows/security.reusable.yml'
awk '{printf "%6d  %s", NR, $0; print ""}' .github/workflows/security.reusable.yml

printf '%s\n' ''
printf '%s\n' '--- Digest/tag-related patterns in workflows'
rg -n '@|container:\s*image:|git://|sha256:|digest' .github/workflows 2>/dev/null || true

Repository: hallelx2/vectorless

Length of output: 9573


🌐 Web query:

Semgrep Docker image latest tag digest semgrep/semgrep

💡 Result:

As of August 3, 2026, the Docker image digest for the semgrep/semgrep:latest tag is sha256:296fc4912420833abfcf5090ec49a81bf1330bb61fc193cd09255f88b8267ba9 [1]. It is important to note that Docker image digests for mutable tags like latest change whenever the image is updated by the maintainers [2][3]. Because the contents of the latest tag are dynamic, you should verify the current digest in your local environment using the following command if you require the exact hash for security or reproducibility purposes: docker inspect --format='{{index.RepoDigests 0}}' semgrep/semgrep:latest Alternatively, you can view the most up-to-date digest directly on the official Docker Hub page for the semgrep/semgrep repository [2][3].

Citations:


Pin the Semgrep container image by digest.

.github/workflows/security.reusable.yml:33 uses semgrep/semgrep, which resolves to the mutable latest image. A tag update can change the scanner code or dependencies without a repository change. Pin an explicit image digest for this Semgrep scan.

🧰 Tools
🪛 zizmor (1.28.0)

[error] 33-33: unpinned image references (unpinned-images): container image is unpinned

(unpinned-images)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/security.reusable.yml at line 33, Update the Semgrep
container image reference in the workflow’s image configuration to use an
explicit immutable digest instead of the mutable semgrep/semgrep tag, preserving
the existing Semgrep scan behavior.

Source: Linters/SAST tools

steps:
- uses: actions/checkout@v4

Check warning

Code scanning / Semgrep OSS

Semgrep Finding: yaml.github-actions.security.github-actions-mutable-action-tag.github-actions-mutable-action-tag Warning

GitHub Actions step uses a mutable tag or branch reference. Tags and branch names can be silently repointed by the action owner, enabling supply-chain attacks — as seen in the trivy-action and kics-github-action compromises. Pin the reference to a full 40-character commit SHA instead, e.g. uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608.
- name: Semgrep scan (industry rulesets)
run: |
semgrep scan \
--config p/owasp-top-ten \
--config p/cwe-top-25 \
--config p/secrets \
--config p/javascript \
--config p/typescript \
--config p/python \
--config p/github-actions \
--sarif --output semgrep.sarif || true

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔒 Security & Privacy | 🟠 Major | 🏗️ Heavy lift

Make detected vulnerabilities fail this security workflow.

These commands force successful exit status after findings. This reusable workflow therefore passes despite Semgrep, Go, Node, Python, and Trivy findings. The caller runs it on pull requests and pushes to main.

  • .github/workflows/security.reusable.yml#L46-L46: remove || true from the Semgrep scan.
  • .github/workflows/security.reusable.yml#L71-L71: remove || true from govulncheck.
  • .github/workflows/security.reusable.yml#L86-L86: remove -no-fail from gosec.
  • .github/workflows/security.reusable.yml#L104-L105: fail when dependency resolution or npm audit fails.
  • .github/workflows/security.reusable.yml#L124-L125: fail when pip-audit or Bandit finds in-scope issues.
  • .github/workflows/security.reusable.yml#L135-L135: use a nonzero Trivy exit code for configured severities.
📍 Affects 1 file
  • .github/workflows/security.reusable.yml#L46-L46 (this comment)
  • .github/workflows/security.reusable.yml#L71-L71
  • .github/workflows/security.reusable.yml#L86-L86
  • .github/workflows/security.reusable.yml#L104-L105
  • .github/workflows/security.reusable.yml#L124-L125
  • .github/workflows/security.reusable.yml#L135-L135
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/security.reusable.yml at line 46, Make the security
workflow fail on configured vulnerability findings by updating
.github/workflows/security.reusable.yml:46-46 to remove Semgrep’s || true, 71-71
to remove govulncheck’s || true, 86-86 to remove gosec’s -no-fail, 104-105 to
propagate dependency-resolution and npm-audit failures, 124-125 to propagate
pip-audit and in-scope Bandit findings, and 135-135 to configure Trivy with a
nonzero exit code for the selected severities.

Sources: Coding guidelines, Learnings

- name: Upload Semgrep SARIF
if: always()
uses: github/codeql-action/upload-sarif@v3

Check warning

Code scanning / Semgrep OSS

Semgrep Finding: yaml.github-actions.security.github-actions-mutable-action-tag.github-actions-mutable-action-tag Warning

GitHub Actions step uses a mutable tag or branch reference. Tags and branch names can be silently repointed by the action owner, enabling supply-chain attacks — as seen in the trivy-action and kics-github-action compromises. Pin the reference to a full 40-character commit SHA instead, e.g. uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608.
with:
sarif_file: semgrep.sarif
continue-on-error: true

go-cves:
name: Go CVEs (govulncheck)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

Check warning

Code scanning / Semgrep OSS

Semgrep Finding: yaml.github-actions.security.github-actions-mutable-action-tag.github-actions-mutable-action-tag Warning

GitHub Actions step uses a mutable tag or branch reference. Tags and branch names can be silently repointed by the action owner, enabling supply-chain attacks — as seen in the trivy-action and kics-github-action compromises. Pin the reference to a full 40-character commit SHA instead, e.g. uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608.
- name: Detect Go module
id: detect
run: |
if [ -f go.mod ]; then echo "is_go=true" >> "$GITHUB_OUTPUT"; else echo "is_go=false" >> "$GITHUB_OUTPUT"; fi
- uses: actions/setup-go@v5

Check warning

Code scanning / Semgrep OSS

Semgrep Finding: yaml.github-actions.security.github-actions-mutable-action-tag.github-actions-mutable-action-tag Warning

GitHub Actions step uses a mutable tag or branch reference. Tags and branch names can be silently repointed by the action owner, enabling supply-chain attacks — as seen in the trivy-action and kics-github-action compromises. Pin the reference to a full 40-character commit SHA instead, e.g. uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608.
if: steps.detect.outputs.is_go == 'true'
with:
go-version: stable
- name: govulncheck (only CVEs that reach real call paths)
if: steps.detect.outputs.is_go == 'true'
run: |
go install golang.org/x/vuln/cmd/govulncheck@latest
govulncheck ./... || true

go-sast:
name: Go SAST (gosec)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

Check warning

Code scanning / Semgrep OSS

Semgrep Finding: yaml.github-actions.security.github-actions-mutable-action-tag.github-actions-mutable-action-tag Warning

GitHub Actions step uses a mutable tag or branch reference. Tags and branch names can be silently repointed by the action owner, enabling supply-chain attacks — as seen in the trivy-action and kics-github-action compromises. Pin the reference to a full 40-character commit SHA instead, e.g. uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608.
- name: Detect Go module
id: detect
run: |
if [ -f go.mod ]; then echo "is_go=true" >> "$GITHUB_OUTPUT"; else echo "is_go=false" >> "$GITHUB_OUTPUT"; fi
- name: gosec
if: steps.detect.outputs.is_go == 'true'
uses: securego/gosec@9e6a9843d7a4a6e3e9a8539b02612c8a4aa3f889 # v2.27.1
with:
args: -no-fail -fmt text ./...

node-cves:
name: Node/TS deps (npm audit)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

Check warning

Code scanning / Semgrep OSS

Semgrep Finding: yaml.github-actions.security.github-actions-mutable-action-tag.github-actions-mutable-action-tag Warning

GitHub Actions step uses a mutable tag or branch reference. Tags and branch names can be silently repointed by the action owner, enabling supply-chain attacks — as seen in the trivy-action and kics-github-action compromises. Pin the reference to a full 40-character commit SHA instead, e.g. uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608.
- name: Detect Node project
id: detect
run: |
if [ -f package.json ]; then echo "is_node=true" >> "$GITHUB_OUTPUT"; else echo "is_node=false" >> "$GITHUB_OUTPUT"; fi
- uses: actions/setup-node@v4

Check warning

Code scanning / Semgrep OSS

Semgrep Finding: yaml.github-actions.security.github-actions-mutable-action-tag.github-actions-mutable-action-tag Warning

GitHub Actions step uses a mutable tag or branch reference. Tags and branch names can be silently repointed by the action owner, enabling supply-chain attacks — as seen in the trivy-action and kics-github-action compromises. Pin the reference to a full 40-character commit SHA instead, e.g. uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608.
if: steps.detect.outputs.is_node == 'true'
with:
node-version: '20'
- name: npm audit (high + critical)
if: steps.detect.outputs.is_node == 'true'
run: |
npm install --package-lock-only --ignore-scripts 2>/dev/null || true
npm audit --audit-level=high || true

python-sast:
name: Python deps + SAST (pip-audit + bandit)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

Check warning

Code scanning / Semgrep OSS

Semgrep Finding: yaml.github-actions.security.github-actions-mutable-action-tag.github-actions-mutable-action-tag Warning

GitHub Actions step uses a mutable tag or branch reference. Tags and branch names can be silently repointed by the action owner, enabling supply-chain attacks — as seen in the trivy-action and kics-github-action compromises. Pin the reference to a full 40-character commit SHA instead, e.g. uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608.
- name: Detect Python project
id: detect
run: |
if ls requirements*.txt pyproject.toml setup.py >/dev/null 2>&1; then echo "is_py=true" >> "$GITHUB_OUTPUT"; else echo "is_py=false" >> "$GITHUB_OUTPUT"; fi
- uses: actions/setup-python@v5

Check warning

Code scanning / Semgrep OSS

Semgrep Finding: yaml.github-actions.security.github-actions-mutable-action-tag.github-actions-mutable-action-tag Warning

GitHub Actions step uses a mutable tag or branch reference. Tags and branch names can be silently repointed by the action owner, enabling supply-chain attacks — as seen in the trivy-action and kics-github-action compromises. Pin the reference to a full 40-character commit SHA instead, e.g. uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608.
if: steps.detect.outputs.is_py == 'true'
with:
python-version: '3.x'
- name: pip-audit (CVEs) + bandit (SAST)
if: steps.detect.outputs.is_py == 'true'
run: |
pip install --quiet pip-audit bandit
pip-audit || true
Comment on lines +123 to +124

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔒 Security & Privacy | 🟠 Major | 🏗️ Heavy lift

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "Repository files related to security workflow / requirements:"
git ls-files | rg '(^|/)(\.github/workflows/security\.reusable\.yml|requirements.*\.txt|pyproject\.toml|setup\.py|setup\.cfg|Pipfile|poetry\.lock|uv\.lock|pip-audit)' || true

echo
echo "Security workflow around relevant lines:"
if [ -f .github/workflows/security.reusable.yml ]; then
  nl -ba .github/workflows/security.reusable.yml | sed -n '1,180p'
fi

echo
echo "pip-audit usage docs/sources locally if installed:"
python3 - <<'PY'
try:
    import subprocess
    p = subprocess.run(["pip-audit", "--help"], text=True, capture_output=True, timeout=20)
    print("STDOUT:")
    print(p.stdout)
    print("STDERR:")
    print(p.stderr)
except FileNotFoundError:
    print("pip-audit command not found")
except Exception as e:
    print(repr(e))
PY

Repository: hallelx2/vectorless

Length of output: 389


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "Security workflow around relevant lines:"
if [ -f .github/workflows/security.reusable.yml ]; then
  awk '{printf "%6d\t%s\n", NR, $0}' .github/workflows/security.reusable.yml | sed -n '1,180p'
fi

echo
echo "Python dependency manifests:"
for f in sdks/python/pyproject.toml sdks/python/uv.lock; do
  if [ -f "$f" ]; then
    echo "--- $f ---"
    awk '{printf "%6d\t%s\n", NR, $0}' "$f"
  fi
done

echo
echo "pip-audit usage docs/sources locally if installed:"
python3 - <<'PY'
try:
    import subprocess
    p = subprocess.run(
        ["python3", "-m", "pip", "install", "pip-audit", "--quiet", "--dry-run"],
        text=True,
        capture_output=True,
        timeout=20,
    )
    print("pip install dry-run:", p.returncode, p.stdout, p.stderr)
    p2 = subprocess.run(["pip-audit", "--help"], text=True, capture_output=True, timeout=20)
    print("pip-audit --help:")
    print(p2.stdout)
    print(p2.stderr)
except FileNotFoundError as e:
    print("pip-audit command not found:", e)
except Exception as e:
    print("Error:", repr(e))
PY

Repository: hallelx2/vectorless

Length of output: 50376


🌐 Web query:

pip-audit help default input mode requirements.txt pyproject.toml uv.lock

💡 Result:

pip-audit defaults to a local environment scan (equivalent to running pip list) when no specific input source or path is provided [1][2]. Regarding your specific files and modes: requirements.txt: You can audit these files by using the -r or --requirement flag [1][3]. For example: pip-audit -r requirements.txt. pyproject.toml: pip-audit supports auditing pyproject.toml files when auditing from a project path (e.g., pip-audit.). Note that at the moment, the tool explicitly identifies pyproject.toml and pylock.*.toml files as supported project files [1][4]. uv.lock: pip-audit does not natively parse or audit uv.lock files directly [1][5]. If you are using uv, the recommended approach for vulnerability scanning is to use the native uv audit command (e.g., uv audit), which is designed to work with your project's lockfile [6][5]. Alternatively, if you must use pip-audit with a project using uv, you would typically need to export the lockfile to a requirements.txt format first using a tool like uv export, then run pip-audit against the resulting requirements file [7][5]. In summary, for standard requirements files, use the -r flag; for project-level scanning of pyproject.toml, use a path-based audit; and for uv projects, prefer the native uv audit command [1][6][5].

Citations:


Audit the Python dependency manifest, not the scanner environment.

pip-audit without arguments scans the installed local environment, so this checks only pip-audit, bandit, and their dependencies. Add the repository Python manifest, such as pip-audit ./pip-audit -r requirements*.txt or the supported uv audit path for sdks/python, so project dependencies are audited.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/security.reusable.yml around lines 123 - 124, Update the
pip-audit invocation in the security workflow to target the repository’s Python
dependency manifest rather than the scanner’s installed environment. Use the
project’s supported manifest or audit path, such as pip-audit with the
requirements files, the project directory, or the uv-based path for sdks/python,
while preserving the existing failure-handling behavior.

Sources: Coding guidelines, Learnings

bandit -r . -ll || true

infra-trivy:
name: Vulns + misconfig (Trivy)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

Check warning

Code scanning / Semgrep OSS

Semgrep Finding: yaml.github-actions.security.github-actions-mutable-action-tag.github-actions-mutable-action-tag Warning

GitHub Actions step uses a mutable tag or branch reference. Tags and branch names can be silently repointed by the action owner, enabling supply-chain attacks — as seen in the trivy-action and kics-github-action compromises. Pin the reference to a full 40-character commit SHA instead, e.g. uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608.
- name: Install Trivy (latest binary — avoids the action's broken setup-trivy pin)
run: curl -sfL https://raw.githubusercontent.com/aquasecurity/trivy/main/contrib/install.sh | sh -s -- -b /usr/local/bin

Check failure

Code scanning / Semgrep OSS

Semgrep Finding: yaml.github-actions.security.gha-curl-pipe-shell.gha-curl-pipe-shell Error

A run: step pipes the output of curl or wget directly into a shell interpreter. This is the "curl | bash" install pattern — if the remote server is compromised or the URL is hijacked, an attacker can execute arbitrary code in your CI runner. Consider downloading the file first, verifying its checksum or signature, and then executing it.
- name: Trivy filesystem scan
run: trivy fs --scanners vuln,secret,misconfig --severity HIGH,CRITICAL --ignore-unfixed --exit-code 0 --no-progress .

# Deepest free SAST = CodeQL. It needs per-repo language detection, so enable it
# per PUBLIC repo via Settings → Code security → Code scanning → Default setup (auto).
# Private repos (control-plane, deploy) rely on the Semgrep + OSV + gosec jobs above.
22 changes: 22 additions & 0 deletions .github/workflows/security.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
name: security

# Caller workflow. This exact file is SYNCED into every target repo by dev-standards,
# so each repo runs the same security scanners on every PR with zero per-repo config.
# It also runs here, scanning dev-standards itself.

on:
pull_request:
push:
branches: [main]

permissions:
contents: read
pull-requests: read
security-events: write

jobs:
security:
# Local reference — the reusable file is synced into THIS repo too, so each repo
# is self-contained and this works whether dev-standards is public or private.
uses: ./.github/workflows/security.reusable.yml
secrets: inherit

Check failure

Code scanning / Semgrep OSS

Semgrep Finding: yaml.github-actions.security.secrets-inherit.secrets-inherit Error

This workflow uses secrets: inherit to pass all of the calling workflow's secrets to a reusable workflow. This violates the principle of least privilege because the called workflow receives access to every secret in the repository, not just the ones it needs. If the called workflow is compromised or sourced from a third party, an attacker gains access to all repository secrets. Instead, explicitly pass only the secrets that the called workflow requires using the secrets: map, e.g. secrets: { MY_SECRET: ${ secrets.MY_SECRET } }.
Comment on lines +12 to +22
Comment on lines +21 to +22

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔒 Security & Privacy | 🟠 Major

Remove secrets: inherit from this caller.

.github/workflows/security.reusable.yml declares no workflow-call secrets and its scanner steps use ${{ github.token }}. secrets: inherit exposes every current and future repository secret to the called workflow. Remove this line. Pass a named secret only if a called step requires one.

As per coding guidelines, security-sensitive workflows must use least privilege and prevent unnecessary secret exposure.

🧰 Tools
🪛 GitHub Check: Semgrep OSS

[failure] 22-22: Semgrep Finding: yaml.github-actions.security.secrets-inherit.secrets-inherit
This workflow uses secrets: inherit to pass all of the calling workflow's secrets to a reusable workflow. This violates the principle of least privilege because the called workflow receives access to every secret in the repository, not just the ones it needs. If the called workflow is compromised or sourced from a third party, an attacker gains access to all repository secrets. Instead, explicitly pass only the secrets that the called workflow requires using the secrets: map, e.g. secrets: { MY_SECRET: ${{ secrets.MY_SECRET }} }.

🪛 zizmor (1.28.0)

[warning] 21-21: secrets unconditionally inherited by called workflow (secrets-inherit): this reusable workflow

(secrets-inherit)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/security.yml around lines 21 - 22, Remove the `secrets:
inherit` entry from the workflow caller that uses
`./.github/workflows/security.reusable.yml`; leave the reusable workflow
reference unchanged, since its scanner steps use `github.token` and declare no
required workflow-call secrets.

Sources: Coding guidelines, Linters/SAST tools

Loading
Loading