Skip to content
This repository was archived by the owner on Jul 24, 2026. It is now read-only.

Add a Beeper installer wired to the shipped device-auth flow#15

Open
Miyamura80 wants to merge 21 commits into
mainfrom
claude/relaxed-planck-dtn99w
Open

Add a Beeper installer wired to the shipped device-auth flow#15
Miyamura80 wants to merge 21 commits into
mainfrom
claude/relaxed-planck-dtn99w

Conversation

@Miyamura80

@Miyamura80 Miyamura80 commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

What

Adds scripts/install-beeper.sh, an agent-friendly helper that wires Beeper into the Edison Watch MCP gateway on macOS. Rebased onto current main, so it targets the shipped browser/device-authorization flow (stdiod #16 + backend scoped device authorization) rather than the old API-key + step-up path.

Why it changed shape since the first draft

Two things landed / were found after the first version:

  1. Device authorization shipped. edison-stdiod login is now a browser/device OAuth flow (no API-key paste), and server add submits a device-scoped request for admin approval. The old machinery this script carried (api-key login, POST /servers/{name}/env token bind, STEP_UP_REQUIRED handling, 409 remove+re-add) no longer applies and is removed.
  2. Beeper serves MCP only from the Desktop app. The headless beeper Server exposes no MCP endpoint (github.com/beeper/cli issue #20); @beeper/desktop-mcp wraps the Desktop app's endpoint, enabled once under Settings > Developers > MCP. A fully unattended install is therefore not possible today, so the script automates the Edison side and prints the exact human steps for the rest instead of pretending they are automatable.

What the script does

Automated:

  • Install prerequisites (npx, edison-stdiod).
  • edison-stdiod login --backend <url> device authorization (idempotent via the persisted client credential; --no-open for headless, --relogin to force).
  • edison-stdiod install to supervise the daemon.
  • edison-stdiod server add beeper --command npx --arg=-y --arg=@beeper/desktop-mcp (submits for approval; server list is the idempotency check).

Printed as explicit action: lines (the human-gated steps):

  • Enable MCP in Beeper Desktop and link chats there.
  • Approve the beeper server once in the dashboard.
  • Set BEEPER_ACCESS_TOKEN on that server in the dashboard. The script discovers a reusable token and prints it masked; under device auth the child's env is delivered by the backend, so the script does not fabricate an env endpoint.

Agent-friendly throughout: every input is a flag or UPPER_SNAKE env var, --dry-run / --yes / --json / --verbose, TTY-aware colors, resource+verb subcommands (install, doctor, status, token, mcp-url, uninstall), and fail-fast errors that print the exact fix.

Also

  • Removes docs/headless-server-add.md: it proposed a device-pairing token to get past the step-up gate, which is exactly what the shipped device-authorization flow does. Superseded.
  • The earlier README platform edit was dropped during rebase; current main already covers platform support and the new login flow.

Test plan

  • bash -n + repo AI-writing hook pass
  • install --dry-run exercises the full flow and exits 0
  • End-to-end on macOS: Beeper Desktop MCP enabled, device auth approved, server approved in dashboard, token set, tool call round-trips

🤖 Generated with Claude Code

@qodo-code-review

Copy link
Copy Markdown

Qodo reviews are paused for this user.

Troubleshooting steps vary by plan Learn more →

On a Teams plan?
Reviews resume once this user has a paid seat and their Git account is linked in Qodo.
Link Git account →

Using GitHub Enterprise Server, GitLab Self-Managed, or Bitbucket Data Center?
These require an Enterprise plan - Contact us
Contact us →

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2 issues found across 2 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="scripts/install-beeper.sh">

<violation number="1" location="scripts/install-beeper.sh:84">
P2: `uninstall --dry-run` fails with the non-interactive confirmation error instead of previewing the uninstall. Treating dry-run as an automatic confirmation would preserve the documented “change nothing” preview behavior.</violation>
</file>

<file name="README.md">

<violation number="1" location="README.md:116">
P3: The README now advertises Linux and Windows supervisors, but `edison-stdiod install --help` still describes `install` as a macOS LaunchAgent command. Updating the CLI help with this documentation change would keep the advertised interface and the runnable help output consistent.</violation>
</file>

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread scripts/install-beeper.sh Outdated
Comment thread scripts/install-beeper.sh

confirm() {
[ "$ASSUME_YES" -eq 1 ] && return 0
[ "$INTERACTIVE" -eq 0 ] && die "refusing to run a confirming action non-interactively: $1" \

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: uninstall --dry-run fails with the non-interactive confirmation error instead of previewing the uninstall. Treating dry-run as an automatic confirmation would preserve the documented “change nothing” preview behavior.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At scripts/install-beeper.sh, line 84:

<comment>`uninstall --dry-run` fails with the non-interactive confirmation error instead of previewing the uninstall. Treating dry-run as an automatic confirmation would preserve the documented “change nothing” preview behavior.</comment>

<file context>
@@ -0,0 +1,452 @@
+
+confirm() {
+  [ "$ASSUME_YES" -eq 1 ] && return 0
+  [ "$INTERACTIVE" -eq 0 ] && die "refusing to run a confirming action non-interactively: $1" \
+    "pass --yes to proceed, or --dry-run to preview"
+  printf '%s [y/N] ' "$1" >&2; read -r ans; [ "$ans" = "y" ] || [ "$ans" = "Y" ]
</file context>

Comment thread README.md Outdated
| --- | --- |
| `login` | Persist credentials + backend URL to `~/.config/edison-stdiod/config.toml` (mode `0600`). Merges on re-run, so you can rotate the API key without re-supplying the backend URL. |
| `install` | Register the OS supervisor unit (macOS LaunchAgent) so the daemon starts at login and restarts on crash. Requires `login` first. |
| `install` | Register the OS supervisor unit (LaunchAgent on macOS, systemd `--user` unit on Linux, Scheduled Task on Windows) so the daemon starts at login and restarts on crash. Requires `login` first. |

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P3: The README now advertises Linux and Windows supervisors, but edison-stdiod install --help still describes install as a macOS LaunchAgent command. Updating the CLI help with this documentation change would keep the advertised interface and the runnable help output consistent.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At README.md, line 116:

<comment>The README now advertises Linux and Windows supervisors, but `edison-stdiod install --help` still describes `install` as a macOS LaunchAgent command. Updating the CLI help with this documentation change would keep the advertised interface and the runnable help output consistent.</comment>

<file context>
@@ -112,7 +113,7 @@ TLDR: `edison-stdiod --help` (and `edison-stdiod <command> --help` for any subco
 | --- | --- |
 | `login` | Persist credentials + backend URL to `~/.config/edison-stdiod/config.toml` (mode `0600`). Merges on re-run, so you can rotate the API key without re-supplying the backend URL. |
-| `install` | Register the OS supervisor unit (macOS LaunchAgent) so the daemon starts at login and restarts on crash. Requires `login` first. |
+| `install` | Register the OS supervisor unit (LaunchAgent on macOS, systemd `--user` unit on Linux, Scheduled Task on Windows) so the daemon starts at login and restarts on crash. Requires `login` first. |
 | `uninstall` | Stop and remove the supervisor unit. Pass `--purge` to also delete the persisted config and logs. |
 | `run` | Run the daemon in the foreground (normally invoked by the service unit). Reads config or accepts `--backend` / `--api-key` / `--device-id` / `--label` flags (also via `EDISON_*` env vars). |
</file context>

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All reported issues were addressed across 1 file (changes from recent commits).

Tip: Review your code locally with the cubic CLI to iterate faster.

Re-trigger cubic

Comment thread scripts/install-beeper.sh Outdated

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All reported issues were addressed across 1 file (changes from recent commits).

Tip: Review your code locally with the cubic CLI to iterate faster.

Re-trigger cubic

Comment thread scripts/install-beeper.sh

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All reported issues were addressed across 1 file (changes from recent commits).

Tip: Review your code locally with the cubic CLI to iterate faster.

Re-trigger cubic

Comment thread scripts/install-beeper.sh Outdated
claude added 17 commits July 24, 2026 10:21
Prototype one-command installer that wires Beeper into the Edison Watch
MCP gateway on macOS: installs prerequisites, brings up a headless Beeper
Server, supervises the stdiod tunnel daemon, registers Beeper's stdio MCP
proxy (npx @beeper/desktop-mcp) as a tunnel child, binds the Beeper access
token, and prints the Edison MCP URL.

Built to be driven by an agent or a human: every input is a flag or env
var, missing inputs fail fast with the exact fix, subcommands follow a
resource+verb pattern, --help carries examples, and --dry-run/--yes/--json
are supported. Interactive prompts only run behind --interactive.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011CRjwx1BeWkTiS97Acyjvx
Ran the script on Linux against the real edison-stdiod binary (built from
this checkout) plus stubbed beeper, which surfaced several defects:

- add_networks leaked IFS=',' into run()'s "$*" logging, so --dry-run
  previewed 'beeper accounts add' calls with commas instead of spaces.
  Split on commas via tr without mutating IFS.
- Token-bind curl printed 'http 000000' (its own 000 plus a '|| echo 000'
  fallback) and had no timeout. Use '|| true' with an empty-check and add
  --connect-timeout/-m so it fails fast.
- --dry-run without --beeper-token aborted at the token step instead of
  previewing. Add a dry-run branch that reports the intent and continues.
- edison-stdiod install failures spilled a raw anyhow backtrace and aborted
  mid-flow via set -e. Export RUST_BACKTRACE/RUST_LIB_BACKTRACE=0 and wrap
  each edison-stdiod step so failures produce an actionable message.
- Skip the live 'server list' idempotency probe under --dry-run.
- The real binary carries a Linux (systemd --user) path, so the hard
  macOS-only guard was stricter than the daemon. Warn on Linux and let the
  daemon report capability, block only truly unsupported platforms.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011CRjwx1BeWkTiS97Acyjvx
Reported: 'install --dry-run' died on a missing 'beeper' CLI instead of
previewing. Rework dependency handling around a single ensure_tool helper:

- --dry-run previews the install command for each missing dep and never
  fails, so you can inspect the whole plan before installing anything.
- Auto-install now requires consent (--install-deps or --interactive) AND
  a confirmation (auto-passed by --yes, prompted under --interactive,
  refused non-interactively without --yes).
- After running an installer, validate the command actually landed on PATH;
  validate the installer itself (brew/cargo) exists before invoking it.
- No consent still fails fast with the exact manual command.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011CRjwx1BeWkTiS97Acyjvx
…tics

Traced the real backend route: POST /api/v1/servers/{name}/env
(UpdateServerEnvRequest) stages the value in the device env_store and
respawns the child. The script's guessed path/body were already correct.

- Drop the 'guessed route' hedging; document the confirmed endpoint.
- The endpoint is admin-only, so surface a clear 401/403 message telling
  the user --ew-api-key must belong to an org admin.
- Distinguish 000 (unreachable / daemon not yet connected) from other codes,
  each with an actionable next step; keep the failure non-fatal.
- Bump the bind timeout to 30s since the call blocks on a child respawn.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011CRjwx1BeWkTiS97Acyjvx
Add a TTY-aware color layer with semantic helpers (step/ok/warn/info) so
both dry-run and real runs read as grouped phases instead of a wall of
white text:

- Colors auto-disable when stderr is not a TTY, when NO_COLOR is set, or
  with the new --no-color flag, so piped and agent output stays a clean,
  parseable ASCII stream (verified: no escape codes leak when piped).
- Phase headers (>>), success (+), info (-), warn (!), and error (x) markers.
- Result block on stdout is gated separately on stdout being a TTY, and the
  copy-paste 'claude mcp add' line stays uncolored so it pastes cleanly.
- --json output is unchanged and never colorized.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011CRjwx1BeWkTiS97Acyjvx
From a real macOS run:
- brew install dumped its full auto-update 'New Formulae' wall. Export
  HOMEBREW_NO_AUTO_UPDATE=1 and HOMEBREW_NO_ENV_HINTS=1 and pass --quiet so
  dependency installs are calm.
- The token step optimistically tried a nonexistent mint endpoint and then
  pointed at a GUI-only path. Beeper exposes no headless token mint, so state
  that plainly: guide the user to create a token once in the app UI and
  re-run with --beeper-token, noting the re-run is fast because deps and the
  Beeper Server are already set up and every step is idempotent.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011CRjwx1BeWkTiS97Acyjvx
Beeper has no headless token mint (OAuth is authorization_code + PKCE), but
the CLI already holds a valid Desktop API bearer after 'beeper setup'. Add
format-agnostic discovery that reuses it so no GUI 'Approved connections'
step is needed:

- discover_beeper_token gathers candidate strings from 'beeper config path'
  and the macOS Keychain, then keeps the first that authenticates against the
  local OAuth userinfo endpoint (discovered from the well-known metadata).
- ensure_beeper_token tries discovery before failing; on success it reuses the
  token silently (only a masked fingerprint is shown, never the secret).
- New 'token' subcommand runs discovery standalone for quick verification.
- All probes are timeout-bounded so a missing server fails fast instead of
  hanging.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011CRjwx1BeWkTiS97Acyjvx
Field findings: 'beeper config path' returns a single file (~/.beeper/
config.json), and the Desktop API did not answer on IPv4, suggesting an
IPv6-only bind. Make token discovery robust:

- Probe the well-known metadata on 127.0.0.1, [::1], and localhost (and
  BEEPER_API_URL if set), using the first that answers as the validation base.
- Scan the whole config directory (dirname of the config file) plus ~/.beeper,
  not just the single config file.
- Report clearly when the Desktop API is unreachable so the cause is obvious.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011CRjwx1BeWkTiS97Acyjvx
…tatus'

Root cause of the empty ~/.beeper and dead 23373: 'beeper status' exits 0
even when no server is configured, so ensure_beeper_server printed 'already
running' and SKIPPED 'beeper setup --server --install'. The server was never
authorized and the Desktop API never started.

- Add beeper_api_base(): probe the well-known metadata across ports
  23373-23378 on 127.0.0.1/localhost/[::1] (honor BEEPER_API_URL), echo the
  first reachable base URL.
- ensure_beeper_server now runs setup when the API is unreachable and
  re-probes after, failing with a clear 'finish the browser authorization'
  message if it still is not up.
- discover_beeper_token reuses beeper_api_base for the same port range.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011CRjwx1BeWkTiS97Acyjvx
Field finding: the CLI stores the bearer verbatim as "accessToken" in
~/.beeper/targets/<name>.json. The previous discovery cat'd the entire
~/.beeper tree (including the 100MB server binary and sqlite DBs), so the real
token was crowded out past the candidate cutoff.

- Extract "accessToken" straight from targets/*.json and try those first,
  remembering the first as the canonical token.
- Limit the broad fallback scan to JSON files under 1M (skip binaries/DBs/logs).
- If no candidate passes the live userinfo check, fall back to the explicit
  accessToken rather than failing (userinfo can be strict about scopes; a truly
  wrong token surfaces as a real child auth error later).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011CRjwx1BeWkTiS97Acyjvx
… child

Real macOS run got all the way through headless token discovery and daemon
install, then failed at 'edison-stdiod server add ... --arg -y': clap reads a
hyphen-leading value in the space form as an unknown flag. Use the --arg=-y
equals form (verified: parses where the space form errors).

Also pass the discovered Desktop API base URL to the child as BEEPER_API_URL
and BEEPER_DESKTOP_BASE_URL, because the server may bind a non-default port
(23374 here) while @beeper/desktop-mcp defaults to 23373.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011CRjwx1BeWkTiS97Acyjvx
A real run reached the daemon and then failed inside 'server add' with a raw
'HTTP 401 Invalid or inactive API key'. Pre-validate the key against
GET /api/v1/servers in ensure_ew_api_key so a bad or wrong-environment key
fails early with an actionable message (including the demo backend hint),
before login/install/server-add run. Non-401 responses proceed; unreachable
backend warns and continues.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011CRjwx1BeWkTiS97Acyjvx
A stale 'beeper' registered under an old device_id caused a 409 (names are
unique per org, so the this-device 'server list' check missed it). On a
conflict, remove the org-level server (admin-only) and re-add it on this
device. If it still fails (e.g. non-admin key), fail with guidance to use
--server-name or delete it in the dashboard. Also skip the live probe cleanly
under --dry-run.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011CRjwx1BeWkTiS97Acyjvx
The 409 self-heal never ran: 'out=$(edison-stdiod server add ...)' as a bare
assignment fails under set -e when the command returns non-zero, so bash exited
silently right after the daemon install (output was captured, nothing printed).
Guard both add captures with '&& rc=0 || rc=$?' so the failure is recorded and
the conflict handler runs.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011CRjwx1BeWkTiS97Acyjvx
Adding a stdio_tunnel server is gated behind interactive step-up re-auth
(backend _require_recent_supabase_login). Detect the STEP_UP_REQUIRED response
and explain the real cause and unblock (add once in the dashboard, or set
STEP_UP_BYPASS_EMAIL_DOMAINS on a non-release backend) instead of the generic
admin-key message.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011CRjwx1BeWkTiS97Acyjvx
Documents the STEP_UP_REQUIRED blocker on POST /api/v1/servers for
stdio_tunnel adds and proposes a device-pairing token flow that keeps the
security gate while making one-command install headless after a one-time
device enrollment.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011CRjwx1BeWkTiS97Acyjvx
…design doc

The step-up blocker this script fought is gone: stdiod #16 (browser device
authorization) + backend scoped device authorization shipped on main. Rewrite
the installer to match, and remove docs/headless-server-add.md (it proposed
exactly what shipped).

- Auth: `edison-stdiod login --backend <url>` device/browser flow instead of
  --api-key. Idempotent via the persisted client credential; --no-open for
  headless, --relogin to force.
- Server add: treat as submit-for-approval (client mcp-requests). Drop the
  step-up handling, the 409 remove+re-add self-heal, and the api-key
  pre-validation, none of which apply under device auth.
- Token: stop POSTing a fabricated /servers/{name}/env route. Under device
  auth the child's env arrives from the backend, so discover a reusable Beeper
  token and print it for the operator to set on the server in the dashboard.
- Scope to the real capability: Beeper serves MCP only from the Desktop app
  (headless server has none, per github.com/beeper/cli issue #20). Probe the
  Desktop API and print the exact human steps (enable MCP, approve server,
  set token) rather than pretending they are automatable.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011CRjwx1BeWkTiS97Acyjvx
@Miyamura80
Miyamura80 force-pushed the claude/relaxed-planck-dtn99w branch from c1d2867 to 4b3f1e8 Compare July 24, 2026 10:24
@Miyamura80 Miyamura80 changed the title Add agent-friendly Beeper install script; fix README platform support Add a Beeper installer wired to the shipped device-auth flow Jul 24, 2026
claude added 3 commits July 24, 2026 10:38
- parse_flags: guard value-taking flags via needval() so a missing value dies
  through the error contract instead of set -u's raw "unbound variable", and
  reject a flag-looking value so a forgotten arg cannot swallow the next flag.
- discover_beeper_token: iterate config dirs as an array so macOS
  "Application Support" (spaced) paths survive; cap the generic scrape and
  bound live validation to 20 candidates at a 3s timeout (was up to 120x5s);
  dedupe candidates preserving order; factor out beeper_userinfo_endpoint.
- Extract server_registered(): one definition of the idempotency check (jq
  precise name match, grep fallback), used by install and doctor.
- Reject stray positional args instead of silently swallowing them.
- Beeper Desktop check is non-fatal now: wire the Edison side and print the
  action rather than stopping at the prerequisite.
- Warn when the saved stdiod backend differs from --ew-backend.
- confirm(): local ans. Clarify DEVICE_LABEL is display-only. Convert two
  `&& || ` chains to if/else. Drop the doubled find redirect.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011CRjwx1BeWkTiS97Acyjvx
When the device is already authorized to a different backend than requested,
only fall back to the saved session when --ew-backend was not given. An
explicit --ew-backend that disagrees now stops with switch guidance instead of
silently targeting the saved backend.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011CRjwx1BeWkTiS97Acyjvx
Real-world testing showed the device-scoped `server add` declares no env, so
the dashboard shows no field to set BEEPER_ACCESS_TOKEN. The admin route
POST /servers/{name}/env still accepts and verifies it, so re-add that push as
an explicit `bind-token` subcommand (needs --ew-api-key admin), to run after
the request is approved. Also correct the approval guidance (Servers/Overview,
"not verified" pre-token is expected) and point the token step at bind-token.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011CRjwx1BeWkTiS97Acyjvx

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 issue found across 1 file (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="scripts/install-beeper.sh">

<violation number="1" location="scripts/install-beeper.sh:606">
P2: Binding exposes a discovered or environment-supplied Beeper credential in curl's process arguments while the request runs. Stream the JSON body through stdin instead of passing it to `--data`.</violation>
</file>

Tip: Review your code locally with the cubic CLI to iterate faster.

Re-trigger cubic

Comment thread scripts/install-beeper.sh
Comment thread scripts/install-beeper.sh
local code
code="$(curl -s -o /dev/null -w '%{http_code}' -m 60 --connect-timeout 5 -X POST "$url" \
-H "Authorization: Bearer ${EW_API_KEY}" -H "Content-Type: application/json" \
--data "$(printf '{"env":{"BEEPER_ACCESS_TOKEN":"%s"}}' "$tok")" 2>/dev/null || true)"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: Binding exposes a discovered or environment-supplied Beeper credential in curl's process arguments while the request runs. Stream the JSON body through stdin instead of passing it to --data.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At scripts/install-beeper.sh, line 606:

<comment>Binding exposes a discovered or environment-supplied Beeper credential in curl's process arguments while the request runs. Stream the JSON body through stdin instead of passing it to `--data`.</comment>

<file context>
@@ -579,6 +580,44 @@ cmd_token() {
+  local code
+  code="$(curl -s -o /dev/null -w '%{http_code}' -m 60 --connect-timeout 5 -X POST "$url" \
+    -H "Authorization: Bearer ${EW_API_KEY}" -H "Content-Type: application/json" \
+    --data "$(printf '{"env":{"BEEPER_ACCESS_TOKEN":"%s"}}' "$tok")" 2>/dev/null || true)"
+  [ -z "$code" ] && code="000"
+  case "$code" in
</file context>
Suggested change
--data "$(printf '{"env":{"BEEPER_ACCESS_TOKEN":"%s"}}' "$tok")" 2>/dev/null || true)"
--data-binary @- < <(printf '{"env":{"BEEPER_ACCESS_TOKEN":"%s"}}' "$tok") 2>/dev/null || true)"

The `token` action line pointed at a dashboard field that does not exist for a
device-auth server. Point it at `bind-token` instead, and add --reveal to print
the full token to stdout on demand (default stays masked).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011CRjwx1BeWkTiS97Acyjvx
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants