Agent Skills: Security Alert: Developer Supply-Chain Threat Filter

>-

UncategorizedID: opendatahub-io/ai-helpers/security-alert

Install this agent skill to your local

pnpm dlx add-skill https://github.com/opendatahub-io/ai-helpers/tree/HEAD/plugins/odh-security/skills/security-alert

Skill Files

Browse the full folder contents for security-alert.

Download Skill

Loading file tree…

plugins/odh-security/skills/security-alert/SKILL.md

Skill Metadata

Name
security-alert
Description
>-

Security Alert: Developer Supply-Chain Threat Filter

Read a set of Hacker News stories and decide which ones are worth alerting on — meaning they plausibly report a supply-chain threat that affects the Red Hat / RHEL ecosystem, Python, or JavaScript/TypeScript. Write those stories to findings.json.

The pipeline controls when this skill runs and has already built the candidate story list. The scope here is semantic analysis only — do not re-fetch or reorder the candidate list, manage state, check registries, or post to Slack. Fetching individual HN thread detail via the Algolia items API is permitted up to the cap in Step 2.

Run the steps below in order. At any early-exit point, stop and take no further action.


Step 1: Read candidate stories

Read stories.json from the workspace:

if [ ! -f stories.json ]; then
  echo '[]' > findings.json
  exit 0
fi
cat stories.json

Each story in the array has:

| Field | Description | |---|---| | id | HN item ID (string) | | title | Story headline | | url | Linked article URL, or HN thread URL if no external link | | hn_url | Direct HN thread link |

If the array is empty, stop here and write an empty findings array to findings.json.


Step 2: Filter each story

Apply two independent tests to each story. A story must pass both to be included. This is a judgment call — do not rely on keyword matching alone.


Test A — Ecosystem relevance (scope gate)

The story must directly involve one of these ecosystems:

Python

  • PyPI packages, pip, pipenv, Poetry, conda, or any Python-specific tooling or runtime
  • Python-language libraries, frameworks, or build tools (e.g. setuptools, wheel, twine)

JavaScript / TypeScript

  • npm, yarn, pnpm, Bun, Deno, or any JS/TS package registry or runtime
  • Node.js tooling, bundlers (webpack, Vite, Rollup, esbuild), or JS/TS-language libraries and frameworks

Red Hat / RHEL ecosystem

  • RHEL, Fedora, CentOS Stream, or RPM-based package repositories (dnf, rpm, COPR, official Red Hat repos)
  • Red Hat products and platforms: OpenShift, OKD, Ansible, Ansible Galaxy/Automation Hub, Quay.io, Podman, Buildah, RHACS, Satellite, Insights, or any registry.redhat.io / registry.access.redhat.com image
  • Red Hat developer tooling: CodeReady, Developer Hub, RHDH, RHEL AI, InstructLab, or official Red Hat SDKs

Exclude stories where the affected ecosystem is clearly something else entirely — Go modules, Rust crates, Ruby gems, Java/Maven, .NET NuGet, Swift, Dart, PHP Composer, etc. — even if the attack technique is novel or interesting.

Ecosystem uncertain? If you cannot confirm the story touches one of the three ecosystems above (even after reading the HN thread), exclude it. Reducing false positives is the priority here.


Test B — Supply-chain attack (threat gate)

The story must also describe an adversarial attack on the software supply chain itself — the dependency, build, or distribution infrastructure has been compromised or weaponized. Specifically:

Malicious or typosquatted packages

  • A package published to npm, PyPI, or another in-scope registry that contains malicious code, credential theft, data exfiltration, or unexpected execution at install or import time
  • A typosquatting campaign or dependency confusion attack

Compromised maintainer accounts or signing keys

  • A registry account taken over to push unauthorized code
  • Package signing keys stolen or misused

Backdoors in open-source dependencies

  • Malicious code inserted into a library, framework, or tool that developers pull as a dependency

Attacks on source code repositories or CI/CD infrastructure

  • Poisoned build steps, compromised CI runners, leaked secrets in pipelines, or unauthorized pushes to a repository
  • A compromised artifact registry, container registry, package mirror, or signing infrastructure

Dependency confusion or namespace hijacking

  • An attacker claiming an internal package name on a public registry

Exclude stories about:

  • IDEs, editors, or tools generating code with insecure patterns — code quality, not a supply-chain attack
  • Platform outages or auth incidents — operational, not adversarial
  • Project governance or policy decisions
  • General vulnerability disclosures that affect only end-users and not the dependency supply chain (e.g. a browser RCE, an OS privilege escalation in an unrelated OS)
  • General data breaches unrelated to developer tooling or source code
  • Security research or proof-of-concept disclosures with no active exploitation of a supply-chain vector
  • Geopolitical or policy news

The test: has the dependency, build, or distribution pipeline been adversarially compromised or weaponized in an in-scope ecosystem? If either part of that test fails, exclude the story.


Fetch the HN thread for any story that is not immediately obvious noise (title makes it unambiguously out of scope). Cap total thread fetches at 15 per run — if you reach the cap, exclude remaining ambiguous stories rather than including them unchecked.

curl -sf "https://hn.algolia.com/api/v1/items/<id>"

If this exits non-zero or returns no data (network error, timeout), decide based on the title alone and proceed — do not let a single fetch failure block the run.

While reading the thread:

  • Apply both tests and decide whether to include this story.
  • Summarize the linked article or post in one sentence. Capture what happened, what was compromised, and who is affected. Store as article_summary.

When uncertain about ecosystem relevance (Test A), exclude. When uncertain about whether a confirmed in-scope story describes a real supply-chain attack (Test B), include — a missed real threat is worse than one extra alert.


Step 3: Write findings.json

Write an array of the stories worth alerting on to findings.json. Write an empty array if no stories were relevant.

Each object:

{
  "hn_id":             "<HN story ID>",
  "package":           "<named package or tool, or empty string if none>",
  "registry":          "npm" | "pypi" | "",
  "versions_affected": "<version range, 'unknown', or empty>",
  "article_summary":   "<one sentence: what happened, what was compromised, who is affected>",
  "hn_title":          "<story headline>",
  "hn_url":            "<https://news.ycombinator.com/item?id=...>"
}

For stories without a specific npm/PyPI package (e.g. a compromised VSCode extension, a GitHub breach, a CI/CD attack): leave package, registry, and versions_affected as empty strings. The article_summary is the primary signal — make it count.

Write the array to findings.json in the workspace and validate it:

cat > findings.json << 'EOF'
[
  { ... }
]
EOF
jq . findings.json >/dev/null

Error handling

| Scenario | Behavior | |---|---| | stories.json missing | Write [] to findings.json; exit 0 | | stories.json present but empty array | Write [] to findings.json; stop | | Thread fetch fails (curl non-zero) | Decide on title alone; proceed | | No stories are relevant | Write [] to findings.json; stop | | Uncertain about ecosystem (Test A) | Exclude it | | Uncertain about threat type (Test B), ecosystem confirmed | Include it |