diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 0000000..3520d6c --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,11 @@ +blank_issues_enabled: true +contact_links: + - name: Security vulnerability + url: https://github.com/jpantsjoha/googlecloud-plugin/security/advisories/new + about: Report privately. Do not open a public issue for a security problem. + - name: Contributing guide + url: https://github.com/jpantsjoha/googlecloud-plugin/blob/main/CONTRIBUTING.md + about: The gate, the skill contract, and the non-negotiable safety rules. + - name: Agent Plugins specification + url: https://agent-plugins.org/specification + about: The packaging standard this plugin conforms to. diff --git a/.github/ISSUE_TEMPLATE/incorrect-gcp-guidance.yml b/.github/ISSUE_TEMPLATE/incorrect-gcp-guidance.yml new file mode 100644 index 0000000..bcfdd6c --- /dev/null +++ b/.github/ISSUE_TEMPLATE/incorrect-gcp-guidance.yml @@ -0,0 +1,54 @@ +name: Incorrect GCP guidance +description: A skill gave advice that is wrong, outdated, or unsafe +labels: ["correctness"] +body: + - type: markdown + attributes: + value: | + This is the most serious failure mode this plugin has — worse than a crash, + because it looks like it worked. Thank you for reporting it. + + - type: input + id: skill + attributes: + label: Which skill + placeholder: cloud-run + validations: + required: true + + - type: textarea + id: guidance + attributes: + label: What it told you + description: Paste the command, config, or advice as given. + render: shell + validations: + required: true + + - type: textarea + id: wrong + attributes: + label: Why it is wrong + description: What actually happens — an error, a deprecated flag, an unsafe default, a billing surprise. + validations: + required: true + + - type: input + id: source + attributes: + label: Authoritative source + description: A Google Cloud docs URL showing the correct behaviour. Every fix needs one. + placeholder: https://cloud.google.com/run/docs/... + validations: + required: true + + - type: dropdown + id: severity + attributes: + label: Severity + options: + - Unsafe — could expose data, over-grant IAM, or cause unexpected cost + - Broken — the command fails or the config is rejected + - Outdated — works, but there is a better or current way + validations: + required: true diff --git a/.github/ISSUE_TEMPLATE/new-skill.yml b/.github/ISSUE_TEMPLATE/new-skill.yml new file mode 100644 index 0000000..92251b2 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/new-skill.yml @@ -0,0 +1,50 @@ +name: Propose a new skill +description: Suggest coverage for a GCP service or capability the plugin lacks +labels: ["skill-request"] +body: + - type: markdown + attributes: + value: | + The plugin is **GCP-only and opinionated by design** — it covers what a + builder actually reaches for, not the whole service catalogue. Make the + case for why this one earns a place. + + - type: input + id: service + attributes: + label: Service or capability + placeholder: Cloud Spanner + validations: + required: true + + - type: textarea + id: tasks + attributes: + label: What would an agent do with it + description: Concrete tasks, not a feature list. What would you ask, and what should happen? + validations: + required: true + + - type: textarea + id: overlap + attributes: + label: Overlap with existing skills + description: | + Which of the 17 existing skills come closest, and where is the boundary? + Every skill must name its neighbours and draw the line, otherwise both + match a request and routing becomes a coin flip. + validations: + required: true + + - type: textarea + id: hazards + attributes: + label: Billable or destructive operations + description: Anything that costs money or cannot be undone needs a warning before the command. + + - type: checkboxes + id: offer + attributes: + label: Contribution + options: + - label: I am willing to draft this skill myself diff --git a/.github/ISSUE_TEMPLATE/skill-not-loading.yml b/.github/ISSUE_TEMPLATE/skill-not-loading.yml new file mode 100644 index 0000000..d320dfc --- /dev/null +++ b/.github/ISSUE_TEMPLATE/skill-not-loading.yml @@ -0,0 +1,52 @@ +name: Skill not loading or routing +description: A skill is missing, or the wrong one activates +labels: ["discovery"] +body: + - type: markdown + attributes: + value: | + Before filing, run `make spec` and `make validate` — they catch most + conformance causes. Include the output below if either fails. + + - type: dropdown + id: harness + attributes: + label: Which agent + options: + - Claude Code + - Antigravity (agy) + - Codex + - Kimi + - Other conformant Agent Plugins client + validations: + required: true + + - type: dropdown + id: kind + attributes: + label: What happened + options: + - No skills appear at all + - Some skills load, others are missing + - The wrong skill activates for my request + validations: + required: true + + - type: input + id: count + attributes: + label: How many skills does your agent see + description: Should be 17. A count of 0 usually means the manifest was rejected; a lower count means individual skills were skipped. + placeholder: "17" + + - type: textarea + id: request + attributes: + label: What you asked, and which skill you expected + description: For routing problems, the exact phrasing matters — routing keys off the skill description. + + - type: textarea + id: validation + attributes: + label: Output of `make spec && make validate` + render: shell diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000..f7cfdce --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,32 @@ +## What and why + + + +## Gate + +- [ ] `make gate` passes locally + + + +## If this touches skills + +- [ ] Frontmatter uses only the closed Agent Skills field set — plugin-specific + keys are namespaced under `metadata` as string values +- [ ] Every trigger in `metadata` also appears in `description` +- [ ] Where scope overlaps another skill, both descriptions name each other and + draw the boundary +- [ ] Every technical claim cites a live Google Cloud doc + +## Safety + +- [ ] No credential values — locations only +- [ ] No `roles/owner` or `roles/editor` in examples +- [ ] Billable or destructive commands carry a warning +- [ ] No public buckets or unauthenticated endpoints without stated intent + +## Records + +- [ ] `CHANGELOG.md` updated if user-facing +- [ ] ADR added for a significant decision +- [ ] `research/coverage-matrix.md` updated if a skill's status changed diff --git a/CHANGELOG.md b/CHANGELOG.md index bcc06a3..92bf4c3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,16 @@ All notable changes to this plugin are documented here. Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/); versioning follows [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [Unreleased] + +### Added + +- `CONTRIBUTING.md` — the gate, the skill contract, and why each rule exists. +- `SECURITY.md` — private reporting, and what counts as a vulnerability in a + plugin that ships instructions rather than a running service. +- Issue templates for incorrect GCP guidance, skills not loading or routing, and + new-skill proposals; plus a pull-request template carrying the safety checks. + ## [0.2.0] — 2026-08-07 **Standards release.** The plugin now conforms to diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..d227af8 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,130 @@ +# Contributing + +Thanks for considering a contribution. This plugin installs a Google Cloud +delivery team into other people's coding agents, so the bar is the same as any +production dependency: if a skill gives bad GCP advice, someone deploys it. + +## Before you start + +Open an issue first for anything beyond a typo. A new skill in particular is +worth discussing — the plugin is **GCP-only and opinionated by design**, and not +every service warrants one. + +## Setup + +```bash +git clone https://github.com/jpantsjoha/googlecloud-plugin.git +cd googlecloud-plugin +pip install pyyaml pytest +make hooks # installs the pre-commit hook that runs `make gate` +``` + +## The gate + +Everything must pass before a PR can merge. CI runs the same checks. + +```bash +make gate +``` + +| Target | What it checks | +|---|---| +| `make spec` | Agent Plugins 1.0.0 conformance — `plugin.json`, `mcp.json`, `skills/` layout | +| `make validate` | Every `SKILL.md` against the Agent Skills specification | +| `make manifest` | The four per-harness manifests parse and agree | +| `make mermaid` | Diagrams render safely on GitHub | +| `make lint` | Every reference URL resolves (HTTP 200) | +| `make test` | Smoke tests | + +`make lint` hits ~100 live URLs. If you get HTTP 429 you have been rate-limited — +wait, don't "fix" the links. CI runs from a different address. + +## Standards this plugin conforms to + +Two open, vendor-neutral specifications, both enforced in CI: + +- [Agent Plugins 1.0.0](https://agent-plugins.org/specification) +- [Agent Skills](https://agentskills.io/specification) + +Verify against the upstream tooling rather than trusting our scripts: + +```bash +uvx --from "git+https://github.com/agentskills/agentskills.git#subdirectory=skills-ref" \ + skills-ref validate skills/cloud-run +uvx check-jsonschema \ + --schemafile https://agent-plugins.org/schemas/1.0.0/plugin.schema.json plugin.json +``` + +## Writing a skill + +Each skill is `skills//SKILL.md` plus a `references/` directory. + +**The frontmatter field set is closed.** Only `name`, `description`, `license`, +`compatibility`, `allowed-tools` and `metadata` are permitted. Add anything else +at the top level and a conformant client **must skip your skill entirely** — it +will not error, it will silently not load. Everything specific to this plugin is +namespaced under `metadata` as **string** values: + +```yaml +--- +name: cloud-run +description: "Deploy and manage containerized workloads on Cloud Run. … Use when the user mentions: deploy to cloud run, serverless container, …" +license: MIT +metadata: + "googlecloud-plugin/version": "0.1" + "googlecloud-plugin/triggers": "deploy to cloud run, serverless container" + "googlecloud-plugin/required-scopes": "run.services.create, run.services.get" + "googlecloud-plugin/mcp-servers": "google-cloud-run" +--- +``` + +Three rules the validator enforces, each of which exists because it broke once: + +1. **`description` is the only thing a conformant client routes on.** It must say + what the skill does *and* when to use it, ending with + `Use when the user mentions: …`. +2. **Every trigger in `metadata` must appear in `description`.** A trigger + recorded only in metadata is unroutable — nothing reads metadata — so it rots + silently while looking like coverage. +3. **Where two skills overlap, each must name the other and draw the line.** + `Use this to author or change IAM; use gcp-security instead to audit an + existing posture.` Without it, both match and routing is a coin flip. + +Keep `SKILL.md` under 500 lines. Move detail into `references/`, which agents +load on demand. + +## Safety rules — non-negotiable + +These are why the plugin exists. A PR that breaks one will be rejected. + +- **No credential values anywhere.** Reference the location, never the secret. +- **Every billable action carries a cost warning** before the command. +- **No `roles/owner` or `roles/editor`** in any example. Least privilege, always. +- **No public Cloud Storage buckets** without explicit, stated design intent. +- **No `--allow-unauthenticated` Cloud Run** without a security rationale. + +## Sources must be real and current + +Every technical claim needs a live Google Cloud reference. No invented flags, no +half-remembered API shapes — check the docs and cite them. `make check` detects +when a cited page has drifted since it was captured. + +## Pull requests + +- Branch from `main`: `feat/description` or `fix/description`. `main` is + protected; PRs are required. +- One logical change per PR. +- Explain **why**, not just what. The diff shows what. +- Update `CHANGELOG.md` under `[Unreleased]` for anything user-facing. +- Add an ADR in `architecture/decisions/` for a significant decision. +- Update `research/coverage-matrix.md` when a skill's status changes. + +## Reporting problems + +- **Wrong GCP guidance** — please open an issue. Incorrect advice is the worst + failure mode this plugin has, more serious than any crash. +- **Security issue** — see [SECURITY.md](SECURITY.md). Don't open a public issue. + +## Licence + +Contributions are MIT, matching the project. diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 0000000..1907637 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,60 @@ +# Security Policy + +## Reporting a vulnerability + +Report privately via +[GitHub Security Advisories](https://github.com/jpantsjoha/googlecloud-plugin/security/advisories/new). +Please don't open a public issue. + +Expect an acknowledgement within a few days. If the report is valid you'll be +credited in the fix, unless you'd rather not be. + +## What counts as a vulnerability here + +This plugin ships no runtime service. It ships **instructions an agent will +follow** and **MCP server declarations an agent will launch**. The interesting +attack surface follows from that: + +- A skill that instructs an agent toward an insecure configuration — over-broad + IAM, a public bucket, an unauthenticated endpoint, a disabled control. +- A prompt-injection vector in skill or reference content that could redirect an + agent's behaviour. +- An `mcp.json` or harness manifest declaration that could execute something + unintended, or a supply-chain concern in a declared package. +- Any credential, token, or private endpoint committed to the repository. + +Incorrect-but-not-dangerous GCP guidance isn't a security issue — please file it +as [Incorrect GCP guidance](https://github.com/jpantsjoha/googlecloud-plugin/issues/new?template=incorrect-gcp-guidance.yml) +instead. It still matters; it just doesn't need private handling. + +## What this plugin does with your credentials + +Nothing. It never asks for, stores, or transmits a credential. + +Authentication is delegated entirely to Application Default Credentials on your +own machine — `gcloud auth application-default login`. The `gcloud` MCP server +declared in `mcp.json` runs locally and inherits your ambient environment; it is +[`@google-cloud/gcloud-mcp`](https://www.npmjs.com/package/@google-cloud/gcloud-mcp), +published by Google. + +`mcp.json` deliberately declares no `env` block. Under +[Agent Plugins 1.0.0](https://agent-plugins.org/specification) only +`${PLUGIN_ROOT}` and `${PLUGIN_DATA}` are expanded — any other `${...}` is passed +through literally, so an env placeholder would be actively misleading rather than +useful. + +## Safety rules enforced in review + +Every contribution is checked against these. They're in +[CONTRIBUTING.md](CONTRIBUTING.md) too, because they're the point of the plugin: + +- No credential values anywhere — reference the location, never the secret. +- No `roles/owner` or `roles/editor` in any example. +- No public Cloud Storage buckets without explicit, stated design intent. +- No `--allow-unauthenticated` Cloud Run without a security rationale. +- Every billable action carries a cost warning before the command. + +## Supported versions + +The latest release on `main` is supported. Fixes ship forward rather than being +backported.