feat(examples): add Google ADK JS Runner guardrails example - #209
Conversation
Add a standalone google-adk-agent example that vendors @arcjet/guard
from arcjet-js@41ef36816e7174f1b0288d28217e63fa14114307 and demonstrates
guardPlugin first on Runner({ plugins }) plus googleAdkContext.
Co-authored-by: David Mytton <davidmytton@users.noreply.github.com>
…y path Accept ADK's GOOGLE_API_KEY alias, rebuild @arcjet/transport from arcjet-js@41ef3681, set onGuardError: "deny" explicitly, and collect only isFinalResponse text. Co-authored-by: David Mytton <davidmytton@users.noreply.github.com>
|
Cursor Agent can help with this pull request. Just |
|
Review the following changes in direct dependencies. Learn more about Socket for GitHub.
|
|
Caution Review the following alerts detected in dependencies. According to your organization's Security Policy, you must resolve all "Block" alerts before proceeding. It is recommended to resolve "Warn" alerts too. Learn more about Socket for GitHub.
Ignoring alerts on:
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment.
Arcjet Review — 🟡 Medium Risk
Decision: Needs Review
Rationale: New self-contained example under examples/google-adk-agent that adds a Google ADK JS agent protected by Arcjet Guard. The example is well-scoped, does not touch production code paths, includes explicit demo-only warnings in the README, validates input with Zod (2000-char message cap, 32 KiB body cap, printable-ASCII conversation id), and reads secrets only from environment variables. Two escalation triggers fire (dependency changes and CI/CD changes via Dockerfile/devcontainer), but both are scoped to the new example directory and additive top-level integrations (README link, root compose.yaml include, publish script workspace entry). The vendored @arcjet/guard and @arcjet/transport packages ship as dist/ tarballs from a specified SHA (documented in vendor/SOURCE.txt) — their source is not in this diff and cannot be reviewed here, but they are Arcjet's own packages pinned to a known commit on their monorepo, and the README clearly explains the reason for vendoring and the plan to unpin. No hardcoded secrets, no auth bypasses of existing routes, no changes to shared infrastructure. Approving despite Medium risk because the change is additive-only and follows the same pattern as the other example directories already in this repo.
Summary of Changes
Adds a new examples/google-adk-agent example demonstrating Arcjet Guard's Google ADK JS integration (guardPlugin + inbound guard() before Runner.runAsync). Includes README, Dockerfile, devcontainer, compose.yaml, a small Node http server (index.ts), the ADK Runner wiring (lib/agent.ts, lib/arcjet.ts), and vendored builds of @arcjet/guard and @arcjet/transport pinned to arcjet-js SHA 41ef36816e7174f1b0288d28217e63fa14114307. Also registers the example in the root README, root compose.yaml, and scripts/prepare-to-publish.ts.
PR Title & Description
These do not match the changes on the branch. They did not change this review's decision, but they will withhold approval once the other findings are resolved. Update them, then add the ai-review label to re-run the review.
- description (incomplete): The description contains only the Cursor Cloud Agent boilerplate and no substantive summary of the change. This PR adds a substantial new example (~28 files) including vendored builds of @arcjet/guard and @arcjet/transport pinned to a specific arcjet-js SHA — a reviewer or future reader would benefit from a short description covering that the example is Google ADK JS (not @google/genai or Python google-adk), that it depends on the unpublished @arcjet/guard/google-adk/v2 subpath and therefore shi
Suggested description
Adds a new `examples/google-adk-agent` example: a Google ADK JS (`@google/adk` 2.x) `Runner` support agent protected by Arcjet Guard's `google-adk/v2` integration.
- Inbound prompt injection screened with `guard()` before `Runner.runAsync` (checks `hasFailedOpen()`).
- `guardPlugin` is registered first on `new Runner({ plugins })` so `beforeToolCallback` gates the `lookup_order` tool with a per-order-id token bucket and PII scanning on the free-text `note` argument.
- Correlation IDs are caller-owned (from the browser) and threaded through `googleAdkContext` / `guardPlugin({ sessionId })`; the server never mints an id for Guard.
This is Google ADK JS, not `@google/genai` and not the Python `google-adk` SDK.
The example depends on `@arcjet/guard/google-adk/v2`, which is not yet published to npm. `@arcjet/guard` and `@arcjet/transport` are vendored from `arcjet/arcjet-js` at commit `41ef36816e7174f1b0288d28217e63fa14114307` (branch `david/cursor/guard-google-adk-v2`); see `vendor/SOURCE.txt`. Repin to the published release once the subpath ships.
Also wires the example into the root `README.md`, root `compose.yaml`, and `scripts/prepare-to-publish.ts`.Escalation Triggers
- Dependency Changes: examples/google-adk-agent/package.json and vendored package.json files added
- CI/CD Pipeline: New Dockerfile, .devcontainer/devcontainer.json, and compose.yaml under examples/google-adk-agent
Notes
PR is large by line count (~5000+ lines of diff) but the bulk is vendored README.md (~2400 lines) and two Apache 2.0 LICENSE files (~200 lines each) — the actual reviewable code (index.ts, lib/agent.ts, lib/arcjet.ts, package.json, Dockerfile, compose.yaml, index.html) is well under the 1000-line threshold. The vendored packages ship compiled dist/ output that is not in the diff and therefore cannot be reviewed here; reviewers should verify the pinned arcjet-js SHA (41ef36816e7174f1b0288d28217e63fa14114307) matches what's expected and confirm the plan to repin once @arcjet/guard/google-adk/v2 is published to npm.
Path filtering: 95 files excluded by ignore paths. 27 of 122 files included in review.
Approval withheld: The PR title or description does not match the branch — see the "PR Title & Description" section. Update them, then add the ai-review label to re-run the review.
Review: 02c12941 | Model: anthropic/claude-opus-4-7 | Powered by Arcjet Review
Parse request.url with URL.pathname so query strings do not 404, reject a non-numeric PORT instead of listening on a random ephemeral port, and import randomUUID from node:crypto. Co-authored-by: David Mytton <davidmytton@users.noreply.github.com>
|
@SocketSecurity ignore npm/@google/adk@2.0.0 |
Adds
examples/google-adk-agent: a Google ADK JS (@google/adk2.x)Runnersupport agent protected by@arcjet/guard/google-adk/v2.Inbound
guard()runs beforeRunner.runAsyncand checkshasFailedOpen().guardPluginis first innew Runner({ plugins })sobeforeToolCallbackrate-limitslookup_orderand scans free-textnoteargs for PII. Default DENY is anArcjetDenialResultdict — ADK skipsrunAsync. Correlation is a caller-ownedsessionIdviagoogleAdkContext— never minted, neverinvocationId.This is Google ADK JS, not
@google/genaiand not the Pythongoogle-adkSDK.The adapter is not on npm yet, so
@arcjet/guardand@arcjet/transport(./http2) are vendored from41ef3681(david/cursor/guard-google-adk-v2). Repin once@arcjet/guard/google-adk/v2publishes.Docs:
/guards/google-adk/. Runexamples/google-adk-agentwithARCJET_KEYandGOOGLE_GENAI_API_KEY(orGOOGLE_API_KEY/GEMINI_API_KEY).