Skip to content
Closed
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
103 changes: 103 additions & 0 deletions .github/workflows/agent-shield.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
# AgentShield — Agent configuration security validation
# See: standards/agent-standards.md
#
# Two-layer approach:
# 1. affaan-m/agentshield action — deep security scan (102 rules across
# secrets, permissions, hooks, MCP servers, and agent config)
# 2. Org-specific structural checks — required files, cross-references,
# SKILL.md frontmatter validation

name: AgentShield

on:
push:
branches: [main]
pull_request:
branches: [main]

permissions:
contents: read

jobs:
agent-shield:
name: AgentShield
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2

# --- Deep security scan via AgentShield CLI ---
# Uses ecc-agentshield (https://github.com/affaan-m/agentshield)
# 102 rules: secrets, permissions, hooks, MCP servers, agent config
- name: AgentShield Security Scan
run: |
npx ecc-agentshield@1.4.0 scan \
--path . \
--min-severity high \
--format terminal

# --- Org-specific structural checks ---
- name: Check required agent files exist
run: |
status=0

if [ ! -f "CLAUDE.md" ]; then
echo "::error::Missing CLAUDE.md"
status=1
fi

if [ ! -f "AGENTS.md" ]; then
echo "::error::Missing AGENTS.md"
status=1
fi

exit $status

- name: Validate cross-references
run: |
status=0

if [ -f "CLAUDE.md" ] && \
! grep -qi 'AGENTS.md' CLAUDE.md; then
echo "::error file=CLAUDE.md::Must reference AGENTS.md"
status=1
fi

if [ -f "AGENTS.md" ] && \
! grep -qi 'petry-projects/\.github' AGENTS.md; then
echo "::error file=AGENTS.md::Must reference org standards"
status=1
fi

exit $status

- name: Validate SKILL.md frontmatter
run: |
status=0

while IFS= read -r file; do
frontmatter=$(awk \
'/^---$/{n++; next} n==1{print} n>=2{exit}' \
"$file")
Comment on lines +78 to +80
Copy link

Copilot AI Apr 7, 2026

Choose a reason for hiding this comment

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

The frontmatter/key detection is overly strict: it only recognizes --- with no surrounding whitespace and keys that start at column 1. If any SKILL.md uses common variations (e.g., --- with trailing spaces, or indented name:/description:), this will incorrectly fail validation. Consider relaxing the patterns (e.g., allow leading/trailing whitespace around --- and optional indentation before keys) to avoid false negatives.

Copilot uses AI. Check for mistakes.

if [ -z "$frontmatter" ]; then
echo "::error file=$file::Missing YAML frontmatter"
status=1
continue
fi

if ! echo "$frontmatter" | grep -q '^name:'; then
Copy link

Copilot AI Apr 7, 2026

Choose a reason for hiding this comment

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

The frontmatter/key detection is overly strict: it only recognizes --- with no surrounding whitespace and keys that start at column 1. If any SKILL.md uses common variations (e.g., --- with trailing spaces, or indented name:/description:), this will incorrectly fail validation. Consider relaxing the patterns (e.g., allow leading/trailing whitespace around --- and optional indentation before keys) to avoid false negatives.

Copilot uses AI. Check for mistakes.
echo "::error file=$file::Missing 'name' field"
status=1
fi
if ! echo "$frontmatter" | grep -q '^description:'; then
Copy link

Copilot AI Apr 7, 2026

Choose a reason for hiding this comment

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

The frontmatter/key detection is overly strict: it only recognizes --- with no surrounding whitespace and keys that start at column 1. If any SKILL.md uses common variations (e.g., --- with trailing spaces, or indented name:/description:), this will incorrectly fail validation. Consider relaxing the patterns (e.g., allow leading/trailing whitespace around --- and optional indentation before keys) to avoid false negatives.

Copilot uses AI. Check for mistakes.
echo "::error file=$file::Missing 'description' field"
status=1
fi
done < <(find . -name 'SKILL.md' \
-not -path '*/node_modules/*' \
-not -path '*/.git/*')

if [ "$status" -eq 0 ]; then
echo "All SKILL.md frontmatter validated."
fi
exit $status
Comment on lines +73 to +103
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

LGTM with minor suggestion.

The awk-based frontmatter extraction and field validation logic is correct. The process substitution < <(find ...) works because GitHub Actions defaults to bash on ubuntu-latest.

For explicit clarity and cross-platform safety, consider adding shell: bash to this step, though it's not strictly required:

- name: Validate SKILL.md frontmatter
  shell: bash
  run: |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/agent-shield.yml around lines 73 - 103, The workflow step
named "Validate SKILL.md frontmatter" relies on bash process substitution and
should be explicit about the shell; update that GitHub Actions step to include a
"shell: bash" property so the run block executes under bash (ensuring the use of
process substitution and bash-specific features in the frontmatter extraction
and validation logic).

Loading