a2a-exposed 0.7.31 → 0.7.32

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/main.mjs CHANGED
@@ -142,10 +142,10 @@ Pairing (OAuth 2.0 device flow, RFC 8628: agents connect without pasting tokens
142
142
  pair set-password the same in a terminal, no echo (the human runs it; never via argv/stdin)
143
143
  pair set-oidc --issuer URL --client-id ID --subjects SUB[,SUB...] [--methods password,oidc] [--secret-stdin]
144
144
  optional OpenID Connect approval on /device and the MCP consent page. The client
145
- secret is APPROVAL_OIDC_CLIENT_SECRET in the environment, or one line on stdin with
146
- --secret-stdin. It is not a flag and it is not saved in config.env. The next
147
- \`npx -y a2a-exposed@latest deploy\` uploads that environment variable as a Worker
148
- secret. Leave the issuer unset and approval stays the password page
145
+ secret deploy uploads is APPROVAL_OIDC_CLIENT_SECRET in the environment you use for
146
+ deploy. --secret-stdin checks one line and discards it, so export the variable
147
+ before deploy. config.env keeps the issuer and client id.
148
+ Leave the issuer unset and approval stays the password page
149
149
  pair list [--json] pending pairing requests (code, claimed name/card, address), the approval mode and
150
150
  when the approval password was set
151
151
  pair approve <code> approve (only with --pairing-approval agent, after your human said yes)
@@ -186,20 +186,20 @@ Control plane account (only when that deployment's login is on)
186
186
  After sign-in, /app shows the account and its agents. Each agent is listed
187
187
  by its hostname. A hosted name opens
188
188
  that agent's page: MCP connectors (revoke needs a recent sign-in), a
189
- message log that does not mark tasks seen, and a SQL download that
190
- replaces a pasted owner token and leaves other credential material out. Peer times are labeled UTC. A pairing
191
- token shows its code. An empty outbound list notes that peers the CLI
192
- added locally are not shown. Sign out is on that
189
+ message log of recent history. Opening this log leaves a pending wake in place until you list the inbox. The SQL download
190
+ is a redacted copy and replaces a pasted owner token. Peer times are labeled UTC. A pairing
191
+ token shows its code. An empty outbound list says peers added with the CLI
192
+ on your machine stay in that CLI. Sign out is on that
193
193
  page. Creating an agent shows the owner token once. The agent page rotates
194
194
  that token after a confirmation and a recent sign-in. The new token is
195
195
  shown once on that agent's page. The previous one stops working immediately.
196
196
  The token is shown only when the stored hash is still that token. A Copy button sits next to it. Without JavaScript the value still copies.
197
- Deleting an agent asks for its name and a recent sign-in. The account page says how many slots remain. A self-hosted inbox has no such delete.
197
+ Deleting an agent asks for its name and a recent sign-in. The account page says how many hosted slots remain. A self-hosted inbox has no such delete.
198
198
  That page is not stored.
199
- FREE_AGENT_LIMIT=2 caps a free account at 2 hosted agents. An agent in your Cloudflare account does not use one of these. An account's own limit overrides it.
200
- Unset, there is no limit. The database rejects another insert.
199
+ FREE_AGENT_LIMIT=2 caps a free account at 2 hosted agents. A Cloudflare agent stays outside that count. An account's own limit overrides it.
200
+ Unset, there is no limit. The database rejects another hosted insert.
201
201
  SIGNUP_ALLOWLIST, when set, admits only those verified emails. Unset, sign-in stays open.
202
- Cloudflare does not match that list. Connect it from the account page after signing in another way.
202
+ Sign-in uses GitHub, Google, or email. Connect Cloudflare from the account page after you sign in.
203
203
  A refusal returns to /app?error=invite and the page says Sign-in is invite-only for now.
204
204
  The control Worker logs social_sign_in_failed before the
205
205
  provider page, social_sign_in_timeout when that sign-in does not
@@ -269,7 +269,7 @@ export async function main(argv) {
269
269
  if (name === "--version" || name === "-v") return console.log(VERSION);
270
270
  if (rest.includes("--help") || rest.includes("-h")) return console.log(HELP);
271
271
  if (name === "pair" && rest[0] === "set-oidc" && rest.some((a) => /^--(secret|client-secret)(=|$)/.test(a)))
272
- throw new CliError("the OpenID Connect client secret is not a flag: export APPROVAL_OIDC_CLIENT_SECRET or pass --secret-stdin (it is not saved in config.env)");
272
+ throw new CliError("export APPROVAL_OIDC_CLIENT_SECRET or pass --secret-stdin. --secret-stdin checks the line and discards it. Deploy uploads only the environment variable");
273
273
  if (name === "pair" && rest[0] === "set-password") {
274
274
  // only --web [--ttl M] [--json]: the password itself never comes from argv, stdin or the environment
275
275
  const extra = rest.slice(1);
package/lib/pair.mjs CHANGED
@@ -120,7 +120,7 @@ export async function setOidc(o, extra = []) {
120
120
  }
121
121
  let sawStdin = false;
122
122
  if (o["secret-stdin"]) {
123
- if (process.stdin.isTTY) die("--secret-stdin reads the client secret from a pipe. Or export APPROVAL_OIDC_CLIENT_SECRET. It is not saved in config.env");
123
+ if (process.stdin.isTTY) die("--secret-stdin reads the client secret from a pipe. Or export APPROVAL_OIDC_CLIENT_SECRET. --secret-stdin checks the line and discards it. Deploy uploads only the environment variable");
124
124
  const chunks = [];
125
125
  for await (const c of process.stdin) chunks.push(c);
126
126
  const secret = Buffer.concat(chunks).toString("utf8").replace(/\r?\n$/, "");
@@ -129,7 +129,7 @@ export async function setOidc(o, extra = []) {
129
129
  const fromEnv = process.env.APPROVAL_OIDC_CLIENT_SECRET || "";
130
130
  if (fromEnv && fromEnv !== secret) console.error("The secret on stdin differs from APPROVAL_OIDC_CLIENT_SECRET. Deploy uploads the environment variable. Neither value was printed or saved.");
131
131
  } else if (!(process.env.APPROVAL_OIDC_CLIENT_SECRET || "").trim()) {
132
- die("export APPROVAL_OIDC_CLIENT_SECRET or pass --secret-stdin. The client secret is not a flag and is not saved in config.env");
132
+ die("export APPROVAL_OIDC_CLIENT_SECRET or pass --secret-stdin. --secret-stdin checks the line and discards it. Deploy uploads only the environment variable");
133
133
  }
134
134
  C.saveConfig({
135
135
  APPROVAL_OIDC_ISSUER: String(o.issuer).trim(),
@@ -141,7 +141,7 @@ export async function setOidc(o, extra = []) {
141
141
  console.error("The client secret was not written there and was not printed.");
142
142
  if (sawStdin && !(process.env.APPROVAL_OIDC_CLIENT_SECRET || "").trim())
143
143
  console.error(`Export APPROVAL_OIDC_CLIENT_SECRET in the environment you use for deploy. This command did not store it.`);
144
- console.error(`The next \`npx -y a2a-exposed@latest deploy\` uploads APPROVAL_OIDC_CLIENT_SECRET from the environment as a Worker secret.`);
144
+ console.error(`The next \`npx -y a2a-exposed@latest deploy\` uploads APPROVAL_OIDC_CLIENT_SECRET only when that variable is set in the environment. A line from --secret-stdin is discarded.`);
145
145
  console.error("Password approval stays available unless --methods oidc (and only once the issuer, client id, secret and allowlist are all set).");
146
146
  }
147
147
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "a2a-exposed",
3
- "version": "0.7.31",
3
+ "version": "0.7.32",
4
4
  "description": "Give any AI agent a public A2A (Agent2Agent) endpoint: Cloudflare Worker inbox + wake webhook or scheduled inbox checks",
5
5
  "type": "module",
6
6
  "bin": {
@@ -2233,7 +2233,7 @@ export async function runOwnerRpc(ctx: TenantContext, ectx: ExecutionContext, in
2233
2233
  data = matched.route.search === "?format=sql"
2234
2234
  ? {
2235
2235
  exportedAt: file.exportedAt,
2236
- sql: "-- Dashboard copy. This is not a backup. Do not load it onto a live inbox.\n"
2236
+ sql: "-- Redacted dashboard copy for reading. The full dump is npx a2a-exposed export with the owner token.\n"
2237
2237
  + "-- Stored token hashes are replaced with redacted: values that do not authenticate, or left out. Ciphertext, push tokens, re-pair hashes, OAuth codes, the approval-password hash, password-setup hashes, and OpenID Connect sign-in rows are omitted.\n"
2238
2238
  + toSql(file, { skip: REDACTED_SQL_SKIP }),
2239
2239
  }
@@ -254,7 +254,7 @@ export function landingPage(m: LandingModel, nonce: string): string {
254
254
  ? `<h2>Connect your agent</h2><p>Agents get a bearer token through the OAuth device flow: your agent asks, and this agent's owner approves the request on the <a href="/device">pairing page</a>. No secrets go through chat. With the a2a-exposed CLI, your agent runs:</p><p><code>${DEFAULT_CLI} connect ${esc(m.base)}</code></p>`
255
255
  : `<h2>Connect your agent</h2><p>Pairing is turned off here: ask this agent's operator for a bearer token.</p>`;
256
256
  return pageShell(m.name, nonce, `${desc}
257
- <p class="n info">This is an <a href="https://a2a-protocol.org/">A2A (Agent2Agent)</a> endpoint, meant for agents rather than people.${m.proxy ? "" : " Messages land in its owner's inbox, which wakes the agent."}</p>
257
+ <p class="n info">This is an <a href="https://a2a-protocol.org/">A2A (Agent2Agent)</a> endpoint for agents.${m.proxy ? "" : " Messages land in its owner's inbox, which wakes the agent."}</p>
258
258
  <table>
259
259
  <tr><th>Agent card</th><td><a href="/.well-known/agent-card.json">${esc(card)}</a></td></tr>
260
260
  <tr><th>JSON-RPC endpoint</th><td><code>POST ${esc(m.base)}/</code></td></tr>
@@ -1,2 +1,2 @@
1
1
  /** Inbox build. Keep this equal to `version` in cli/package.json. */
2
- export const VERSION = "0.7.31";
2
+ export const VERSION = "0.7.32";
@@ -627,7 +627,8 @@ test("TenantStore.owner runs an allowlisted owner call and does not return a pee
627
627
  const sql = (sqlDump.body as { sql?: string }).sql ?? "";
628
628
  assert.match(sql, /note \[redacted\] end/);
629
629
  assert.match(sql, /redacted:ada/);
630
- assert.match(sql, /Do not load it onto a live inbox/);
630
+ assert.match(sql, /Redacted dashboard copy for reading/);
631
+ assert.equal(sql.includes("not a backup"), false);
631
632
  assert.equal(sql.includes(pasted), false);
632
633
  assert.equal(sql.includes("oauth_codes"), false);
633
634
  assert.equal(sql.includes("oidc_txns"), false);