From 621e9f5c38ad25922dd1bd0ed9b6fed9a7c63599 Mon Sep 17 00:00:00 2001 From: Altay Date: Sun, 25 Oct 2026 17:56:34 +0300 Subject: [PATCH 1/2] docs: fold crash-reporting privacy into README and drop architecture doc --- AGENTS.md | 5 +- README.md | 16 ++-- docs/architecture.md | 129 --------------------------------- scripts/check-architecture.mts | 3 +- 4 files changed, 15 insertions(+), 138 deletions(-) delete mode 100644 docs/architecture.md diff --git a/AGENTS.md b/AGENTS.md index 587c1db..9034a36 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -3,7 +3,7 @@ ## Repo - `@putdotio/cli`, the `putio` binary, shipped through npm, Homebrew, and standalone binaries. -- Code lives in `src/*`; layer rules are in [Architecture](docs/architecture.md). +- Code lives in `src/*`. - `skills/putio-cli` is the consumer skill that ships in the npm package. - Contributor setup is in [Contributing](CONTRIBUTING.md). @@ -20,7 +20,7 @@ Run `pnpm exec vp install`, `pnpm exec vp config`, then ## Development Guidance -- `README.md` is for users, `CONTRIBUTING.md` for contributors, `docs/*` for architecture, `skills/*` for consumer usage. +- `README.md` is for users, `CONTRIBUTING.md` for contributors, `skills/*` for consumer usage. - Keep command modules thin; shared behavior goes in Effect services and layers with `Schema` boundaries and tagged errors. - JSON output is the machine contract; terminal output is a separate adapter. - When commands, flags, output, auth, `automation`, or `describe.version` change in a way consumers need, update [`README.md`](README.md), [`skills/putio-cli/SKILL.md`](skills/putio-cli/SKILL.md), and its references in the same change. @@ -41,6 +41,7 @@ does not cover. ## Hazards - The built binary authenticates with `PUTIO_CLI_TOKEN` when it is set, otherwise with the profile in `~/.config/putio/config.json` (or under `XDG_CONFIG_HOME`). `describe` and `whoami` only read; file, transfer, and upload commands change that real account. For isolated state, unset `PUTIO_CLI_TOKEN` and point `PUTIO_CLI_CONFIG_PATH` at a scratch file. +- README `Crash Reporting` is a public privacy promise. Any change to what a crash event carries or when it is sent updates that section in the same change. ## Delivery diff --git a/README.md b/README.md index 2dbd706..9908b9e 100644 --- a/README.md +++ b/README.md @@ -159,14 +159,20 @@ putio telemetry enable ``` A report holds a random ID, timestamp, failure category, runtime labels, and the -release. It never holds the error, credentials, config, arguments, request data, -paths, or identifiers. The [crash-reporting policy](./docs/architecture.md#crash-reporting-policy) -has the details. Send deletion requests to the private contact in the -[put.io security policy](https://github.com/putdotio/.github/blob/main/SECURITY.md). +release. It never holds the error message or stack, credentials, config, +command arguments, request data, paths, or device or user identifiers. + +- Only unexpected crashes report; ordinary command errors never do. +- One report per run at most. You still get the local error, and exit waits at + most 250 ms for delivery. +- Builds from source send nothing. +- If the config file exists but cannot be read or parsed, that run sends nothing. +- `disable` stops future reports; it does not delete sent ones. Send deletion + requests to the private contact in the + [put.io security policy](https://github.com/putdotio/.github/blob/main/SECURITY.md). ## Docs -- [Architecture](./docs/architecture.md) - [Contributing](./CONTRIBUTING.md) - [Security](https://github.com/putdotio/.github/blob/main/SECURITY.md) diff --git a/docs/architecture.md b/docs/architecture.md deleted file mode 100644 index ead1a1a..0000000 --- a/docs/architecture.md +++ /dev/null @@ -1,129 +0,0 @@ -# CLI Architecture - -The CLI is agent-first and Effect-native. - -```mermaid -flowchart TD - A["Command adapters"] --> B["Workflow services"] - B --> C["Domain request/response schemas"] - B --> D["Infrastructure services"] - D --> E["put.io SDK"] - D --> F["Filesystem / terminal / runtime"] - B --> G["Output service"] -``` - -## Layers - -- **Command adapters** (`effect/cli`): parse flags and raw `--json` input, - decode it into typed requests, call a workflow, and pick the output mode. -- **Workflow services**: own orchestration, reach other services through - Effect layers, and return typed results and tagged errors. -- **Infrastructure services**: terminal and runtime, output rendering, config - and profile-aware auth, persisted state, and SDK access through the SDK's live - layer and fetch transport. - -## Invariants - -- Production modules never call `Effect.run*`; `src/bin.ts` and `src/sea.ts` - run the program through `NodeRuntime.runMain`. `check:architecture` enforces - this. -- External data is parsed once at the boundary, then trusted. -- Commands stay thin, so workflow tests matter more than command tests. -- Structured output is the contract for scripts and agents; terminal rendering - is an adapter over it. - -## Agent Contract - -- `describe` is schema-backed and lists every command's purpose, flags, raw - JSON payload shapes, and the `automation` metadata, so agents need no prose - docs. -- Every leaf command in `describe` has structured output; root and group - commands such as `putio auth` print help text. -- Write commands accept raw `--json` input and `--dry-run`. -- Read commands accept `--fields`; streaming reads also accept cursor-backed - `--page-all`. -- Field selectors and identifier-like inputs are validated before API calls. -- Auth selection order: `PUTIO_CLI_TOKEN`, then `--profile`, then - `PUTIO_CLI_PROFILE`, then the default profile, then the legacy single-token - config. -- Structured renderers redact sensitive values and list prompt-injection-like - API text in `_meta.agentSafety.untrustedTextPaths`. -- [`skills/putio-cli`](../skills/putio-cli/SKILL.md) is the versioned consumer - skill. - -## Crash-Reporting Policy - -### Decision - -Crash reporting is an enabled-by-default diagnostic, not product analytics. It -goes to the dedicated `putio/putio-cli` Sentry project: US-hosted, Node -platform, owned by the Sentry `frontend` team. - -`putio telemetry disable` writes `telemetry_disabled: true` to the private CLI -config; `enable` removes it; `status` reports it without authentication. That -boolean is the only preference. Startup reads it before initializing Sentry. A -missing config keeps reporting on; an unreadable, invalid, or unexpected config -turns it off for that process. - -Release artifacts embed a validated DSN at build time. Source and pull-request -builds have none, so they never initialize Sentry or install crash handlers. CI, -agents, and other non-interactive runs use the same default and the same -persisted preference; `DO_NOT_TRACK` is not a separate control. Command -behavior is otherwise identical online and offline. - -### Failure Boundary - -Expected typed Effect, CLI, SDK, and API failures stay ordinary command errors. -Unexpected Effect defects, uncaught exceptions, and unhandled rejections may -send one synthetic event per process. - -- Effect defects render the local error to stderr first. -- Global handlers remove themselves after the first fatal event, flush, and - replay the original exception or rejection to Node. -- Stdout stays reserved for command results; ordinary failures keep exit - status 1. -- Interrupt-only causes go straight to the Node runtime, so signal semantics - hold. -- The flush deadline is 250 ms with no retry. Capture and flush failures are - dropped. Reporting never replaces the local error or delays exit past that - bound. - -### Data - -Events are built from an allowlist and projected through it again just before -transport. The transport accepts only the expected event ID and failure -category, drops SDK-internal or malformed envelopes, and rebuilds the envelope -instead of forwarding SDK output. - -An event carries only: a random event ID and timestamp, a fixed message and -component and platform labels, one of three failure-category tags -(`effect_defect`, `uncaught_exception`, `unhandled_rejection`), the fixed -`production` environment, fatal level, logger, message-and-category -fingerprint, and the release `@putdotio/cli@`. The envelope also -carries the public DSN routing metadata Sentry requires. - -The original error, message, and stack never reach Sentry. Events also exclude -tokens, profiles, environment variables, config values, command names and -arguments, API bodies, URLs, paths, filenames, payloads, server text, -breadcrumbs, and device or user identifiers. Default integrations, client -reports, logs, tracing, server-name detection, PII capture, breadcrumbs, and -stack attachment are off. No stack is sent, so there is no source-map upload. - -### Operations - -Release builds read `PUTIO_CLI_SENTRY_DSN` from the protected `release` -environment, validate it as an HTTPS Sentry DSN, and fail when it is missing or -invalid. The DSN is a public routing key; Sentry auth and admin tokens stay out -of the repository and artifacts. The `frontend` team owns the project and its -support path. Events follow the put.io Sentry organization's retention and serve -debugging only. - -Removal requests and sensitive reports go to the private contact in the -[put.io security policy](https://github.com/putdotio/.github/blob/main/SECURITY.md). -`putio telemetry disable` stops future events; it does not delete delivered -ones. - -A local bug report should carry the CLI version, install method, OS name, -interactive or CI context, command name, output mode, and the smallest useful -sanitized stderr excerpt. It must not carry command arguments or any excluded -data above. diff --git a/scripts/check-architecture.mts b/scripts/check-architecture.mts index c557ba5..a903a9c 100644 --- a/scripts/check-architecture.mts +++ b/scripts/check-architecture.mts @@ -21,8 +21,7 @@ for (const file of files) { violationCount += 1; process.stderr.write( `${file}:${index + 1}: Effect.run* is forbidden in production modules. ` + - "Return the Effect and execute it through NodeRuntime.runMain in src/bin.ts or src/sea.ts. " + - "See docs/architecture.md.\n", + "Return the Effect and execute it through NodeRuntime.runMain in src/bin.ts or src/sea.ts.\n", ); } } From 596e4c8b5cbf9302890764785853b39932e378bf Mon Sep 17 00:00:00 2001 From: Altay Date: Sun, 25 Oct 2026 18:18:49 +0300 Subject: [PATCH 2/2] docs: link unshipped files by URL; comment the credentialed no-cache rule --- .github/workflows/ci.yml | 6 +++--- AGENTS.md | 6 +++--- CONTRIBUTING.md | 6 +++--- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9b5909f..a9cfa2b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -144,7 +144,7 @@ jobs: uses: ./.github/actions/setup-vp # zizmor: ignore[self-repository] with: node-version-file: ".node-version" - cache: false + cache: false # credentialed job: never share a dependency cache with pull requests - name: Install dependencies run: vp install @@ -265,7 +265,7 @@ jobs: uses: ./.github/actions/setup-vp # zizmor: ignore[self-repository] with: node-version-file: ".node-version" - cache: false + cache: false # credentialed job: never share a dependency cache with pull requests - name: Install dependencies run: vp install @@ -345,7 +345,7 @@ jobs: uses: ./.github/actions/setup-vp # zizmor: ignore[self-repository] with: node-version-file: ".node-version" - cache: false + cache: false # credentialed job: never share a dependency cache with pull requests - name: Install dependencies run: vp install diff --git a/AGENTS.md b/AGENTS.md index 9034a36..41e96fe 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -46,9 +46,9 @@ does not cover. ## Delivery - Pull requests squash-merge to `main`; every merge must be releasable. -- The squash commit's type decides the release ([`.releaserc.json`](.releaserc.json)); a release ships npm, binaries, and the Homebrew formula at once ([`ci.yml`](.github/workflows/ci.yml)). -- [`install.sh`](install.sh) on `main` is the live `curl | sh` installer; a merge changes it at once. -- Partial release: dispatch `CI` from `main` with the existing tag as `release_tag` ([`ci.yml`](.github/workflows/ci.yml)). Use [`Backfill Release Assets`](.github/workflows/backfill-release-assets.yml) only for releases published before draft-first releases. +- The squash commit's type decides the release ([`.releaserc.json`](https://github.com/putdotio/putio-cli/blob/main/.releaserc.json)); a release ships npm, binaries, and the Homebrew formula at once ([`ci.yml`](https://github.com/putdotio/putio-cli/blob/main/.github/workflows/ci.yml)). +- [`install.sh`](https://github.com/putdotio/putio-cli/blob/main/install.sh) on `main` is the live `curl | sh` installer; a merge changes it at once. +- Partial release: dispatch `CI` from `main` with the existing tag as `release_tag` ([`ci.yml`](https://github.com/putdotio/putio-cli/blob/main/.github/workflows/ci.yml)). Use [`Backfill Release Assets`](https://github.com/putdotio/putio-cli/blob/main/.github/workflows/backfill-release-assets.yml) only for releases published before draft-first releases. ## Skills diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 90327a2..40afcd9 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -2,7 +2,7 @@ ## Setup -Use the Node version in [`.node-version`](./.node-version), then install +Use the Node version in [`.node-version`](https://github.com/putdotio/putio-cli/blob/main/.node-version), then install dependencies and the tracked Git hooks. Pre-push runs the same `verify` gate as CI. @@ -44,12 +44,12 @@ Pin `effect` to the version the pinned put.io SDK depends on; `smoke:pack` fails if the packed install resolves more than one. The build bundles the SDK, so the CLI and SDK share one Effect runtime. If an SDK release needs an Effect API the pinned runtime lacks, add a pnpm patch and register it in -[`pnpm-workspace.yaml`](./pnpm-workspace.yaml). +[`pnpm-workspace.yaml`](https://github.com/putdotio/putio-cli/blob/main/pnpm-workspace.yaml). ## Release Setup Maintainers keep these provider settings in sync with -[`ci.yml`](.github/workflows/ci.yml); the release fails without them. +[`ci.yml`](https://github.com/putdotio/putio-cli/blob/main/.github/workflows/ci.yml); the release fails without them. - GitHub Environment `release`: holds the credentials `ci.yml` reads, no approval, `main` only. - `putio-ci` GitHub App: Contents read and write on `putio-cli` and `putdotio/homebrew-tap`.