UNPKG

akm-cli

Version:

akm (Agent Knowledge Manager) — a portable, local-first capability library for AI agents. Discover, load, share, and improve reusable skills, scripts, workflows, and knowledge across any shell-capable coding agent, including Claude Code, OpenCode, and Cur

47 lines (46 loc) • 2.52 kB
// This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at https://mozilla.org/MPL/2.0/. /** * `stash-git-exposure` surfaces advisory for `akm health` (08-F1). * * Versioning the stash is a supported use case (private-remote backup), so a * tracked `env/`/`secrets/` directory is NOT wrong by itself. The leak moment * is when secret assets are git-TRACKED **and** a remote is configured — only * then can a `git push` exfiltrate tokens/keys. Warn on exactly that * combination; stay silent on the tracked-but-no-remote opt-in so the advisory * catches the exposure without nagging the intentional backup. */ import { spawnSync } from "node:child_process"; const realGit = (stashDir, args) => { const result = spawnSync("git", ["-C", stashDir, ...args], { encoding: "utf8", timeout: 5_000 }); return { ok: result.status === 0, stdout: (result.stdout ?? "").trim() }; }; /** * Build the `stash-git-exposure` advisory, or `undefined` when there is nothing * to warn about (not a git repo, no tracked env/secret assets, or no remote). */ export function collectStashExposureAdvisory(stashDir, git = realGit) { // Not a git work tree → nothing to expose. if (!git(stashDir, ["rev-parse", "--is-inside-work-tree"]).ok) return undefined; const tracked = git(stashDir, ["ls-files", "--", "env", "secrets"]); if (!tracked.ok || tracked.stdout.length === 0) return undefined; // no secret assets tracked const remotes = git(stashDir, ["remote"]); if (!remotes.ok || remotes.stdout.length === 0) return undefined; // no push target → no leak path const trackedFiles = tracked.stdout.split("\n").filter(Boolean); const preview = trackedFiles.slice(0, 5).join(", ") + (trackedFiles.length > 5 ? `, +${trackedFiles.length - 5} more` : ""); return { name: "stash-git-exposure", kind: "deterministic", status: "warn", confidence: "high", message: `${trackedFiles.length} env/secret file(s) are git-tracked AND a remote is configured — ` + `a 'git push' can leak tokens/keys (${preview}). ` + "Run 'git rm --cached' on them (a .gitignore rule alone does NOT untrack already-tracked " + "files) and then add env/+secrets/ to .gitignore to prevent recurrence (akm bundle create scaffolds it).", evidence: { trackedSecretFiles: trackedFiles }, }; }