mirror of
https://github.com/stablyai/orca.git
synced 2026-10-08 00:02:38 +00:00
6d1a97ef985257cf55c2345b6e8180eeb276fecc
7
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
5fa290fa50 |
feat(secrets): warn in Settings when a credential is stored unencrypted (#24048)
* feat(secrets): warn in Settings when a credential is stored unencrypted When no OS keyring is usable, the MiniMax stores write the credential as a plaintext envelope and say so with a console.warn nobody reads. The users this affects are exactly the ones who never see a main-process log, so in practice they were told nothing (#21827). Report it where the credential is managed instead. Each store gains a protection reader, the status IPC carries it, and Settings renders a warning next to the credential it applies to. Keyed on the stored bytes, not isEncryptionAvailable(): a credential saved before a keyring existed stays plaintext until it is saved again, so reporting current capability would call it protected while the file says otherwise. The readers parse the envelope kind without decrypting, so opening Settings cannot provoke a keychain prompt. The console.warn stays. It carries no secret material, and it is still the only signal on a headless host with no Settings window. * feat(secrets): extend the unsealed-credential warning to every affected store The speech key, Linear tokens, Jira tokens and the Bitbucket credential have the same plaintext fallback the MiniMax stores do, and the same console-only warning nobody reads. Add a shared `readCredentialFileProtection` for the four stores that write bare ciphertext with no envelope, classifying with the same printable-UTF-8 test `readStoredCredentialToken` already uses — so the reporter cannot drift into disagreeing with the reader about the same bytes. Linear and Jira report across every stored workspace/site rather than the active one: sealing is a host-wide property, so a second workspace stored while the keyring was missing is exposed even when the active one is sealed. Both fields are optional, so an older remote host that omits them reads as unknown rather than as sealed. Bitbucket reports null for env-supplied auth, where Orca stores nothing and has no claim to make. Also fixes the credential-connection test double, whose identity-function `encryptString` wrote a readable token — faithful enough for a round-trip assertion, but it made the suite assert that a sealed credential was exposed. * chore(i18n): extract the unsealed-credential notice strings CI's localization-extraction gate requires every translate() key to exist in the primary catalog. Inserted in place rather than re-sorting the file, which is not fully sorted and would have produced a 17k-line diff. * test(web): pin the null protection fields on the desktop-only MiniMax bridge The web bridge reports no protection because it stores nothing; the shape assertions had to move with it. |
||
|
|
dcaef9dee5 |
test: retire relay, preload and shared cases that re-prove an owned contract (#24007)
Audit sweep over `src/relay`, `src/preload` and `src/shared` (1,087 test files reviewed). 101 case declarations removed across 40 files, 6 test files deleted outright, 1,143 lines gone. Executed-case count falls further, since several removals were `it.each` tables. Dominant patterns, by frequency: - Self-comparisons that cannot fail: `expect(f(x)).toBe(f(x))`, `JSON.parse(JSON.stringify(literal))` deep-equalling the literal for a type with no codec, and `normalizeKeyToken(t) === normalizeKeyToken(t)` presented as proof of memoization. - Object literals asserting their own fields back, where the guarantee comes from the type annotation and the runtime assertion cannot fail. - Copied inventories: constants compared to their own initializers, and a function returning a copy of an exported constant checked against that constant's literal contents. - Duplicate invocations of a contract owned at a stronger boundary, including provider-local replays of a shared helper. - Table rows varying a field production never reads, so every row runs one path. - Names promising more than the input exercises: a "Windows launch" case in a module with no platform input, and a case whose named branch is never entered. Two production symbols go with them, each a test-only export whose sole caller was a deleted case: - `getGitHubProjectRefInputByteLength` — a one-line forward to `getClipboardTextByteLength`. The real bound (`GITHUB_PROJECT_REF_INPUT_MAX_BYTES`) and its guard stay. - `GRAB_STYLE_PROPERTIES` — an intended shared source of truth that nothing ever consulted; the property set is hand-enumerated at three independent sites. One case was deliberately restored and strengthened rather than dropped. The relay integration suite is the only place the real `SshChannelMultiplexer` is wired to `RelayDispatcher`, so it reaches transport behavior the handler suites cannot (they use `createMockDispatcher`). Its `fs.writeFile` roundtrip is the one case producing a void result, and `JSON.stringify` drops an absent `result` member — a shape no other surviving case exercises. Restored with an assertion pinning what the client actually observes: `null`, not `undefined`. That assertion failed on first run, so the fact was previously unasserted anywhere. One deletion was reverted mid-audit. A case asserting that optional fields stay invisible to "old attach and ready decoders" builds those decoders from `z.object` schemas declared in the test file, so it demonstrates zod's unknown-key stripping rather than anything shipped. It is nonetheless the only forward-compatibility coverage these envelopes have, and `reliability-gates.jsonc:6232` names it as evidence verbatim, so it stays. Note that `check-reliability-gates.mjs` passed both with and without it: the script resolves manifest paths and commands, and does not check that a named assertion still corresponds to a live case. Kept deliberately: everything a reliability gate cites as evidence; the three `registers all expected handlers` RPC manifests (a dropped registration is a silent wire break no type checker catches, and one carries the STA-4571 `pty.ackData` ratchet); the `child-process` direct-import ratchet; and prototype-spy cases paired with a `.repeat(10_000)` input, which assert a real memory bound rather than merely forbidding a technique. Verified: `pnpm test src/shared src/relay src/preload` (1073 files, 11996 passed, 1 pre-existing `it.fails`, 131 skipped), `pnpm tc` after clearing `.tsbuildinfo`, `check-reliability-gates.mjs` (140 gates), `check:code-quality:changed` (0 new findings). |
||
|
|
838769d73e |
fix(linear): accept team keys that start with a digit (#23423)
Fixes #23422 |
||
|
|
c5d43b8a24 |
Avoid Linear read re-fetches when workspace scope is unchanged (#17529)
* Avoid Linear read re-fetches when workspace scope is unchanged Derive a stable scope signature that captures only the connected state and workspace identity, ignoring volatile metadata like displayName. Use this in dependency tracking so Linear searches don't re-run on status updates that don't affect which issues can be queried. * Expand workspace scope to detect credential and org changes Cache invalidation key now includes credentialRevision and organizationUrlKey for both workspace and viewer, ensuring Linear reads re-fetch when credentials rotate or organizations are renamed — fields that affect what read operations return. * Include activeWorkspaceId in workspace scope signature URL lookup falls back to the active workspace even when all workspaces are selected, so activeWorkspaceId must be part of the scope signature to ensure reads are keyed correctly. |
||
|
|
3fca1d1648 |
fix(linear): unbound list-issues by default, surface truncation, bind cursor workspace (#15824)
Fixes STA-5076. list-issues capped at 50 by default and hard-clamped at 250, with hasMore buried under result.meta and no stderr warning for --json, so a page that stopped early read as a complete answer. Omitting --limit now walks Linear's pages until they run out (meta.limit is null), and --limit <n> is the only cap, paging past Linear's 250-per-request maximum to reach it. result.truncated sits next to result.issues and is set only when a cap actually held results back; human output prints "truncated: showing N". The read still has to fit the CLI's 60s RPC budget, so a 20s wall-clock deadline and a 200-page ceiling stop the walk early and report truncated with a continuation cursor rather than failing the command. Also: - issued --cursor values bind the resolved workspace, so call -> nextCursor -> call works without --workspace; raw Linear cursors still need one and now carry nextSteps - issued cursors whose payload smuggles back `all` or an empty workspace are rejected at decode, since either would widen the read past the bound workspace - JSON issue rows carry priorityLabel (none/urgent/high/medium/low), matching orca linear priority set - truncated and priorityLabel are optional on the wire, so a host that predates either is not read as "complete"; readers fall back to meta.hasMore - the truncation line prints the rows actually rendered, so a remote result with no meta.returned cannot print "showing undefined" |
||
|
|
77f23b013f |
refactor(shared): drop the shared/types barrel and import from the real modules (#14447)
#14397 split `shared/types.ts` into 46 per-domain modules but kept the path as a re-export barrel so the import sites did not have to change. This removes the barrel: every consumer now imports from the module that actually declares the type, and `src/shared/types.ts` is deleted. Barrels hide where a type lives, make every consumer look like it depends on the whole domain, and let an unrelated edit invalidate a module that ~2,000 files transitively import. 2,323 import declarations across 2,321 files. Rewritten mechanically: each specifier was resolved to an absolute path via the TypeScript AST and recomputed, rather than string-substituted, so alias forms (`@/../../shared/ types`) and per-specifier `type` modifiers survive. Four cases the mechanical pass had to handle, each found by a gate rather than by reading the diff: - Modules inside `src/shared` import the barrel as `./types`, not `shared/types`. A pre-filter on the latter string skipped 176 of them and left imports dangling at a deleted file, which surfaced as confusing `Property 'x' is optional in type 'Repo' but required in Pick<Repo, ...>` errors rather than "module not found". - The barrel RENAMED one type on the way through (`WorkspaceSource as WorkspaceCreateTelemetrySource`), so the original name in the owning module has to be re-aliased at each consumer. - Three test files put `;(globalThis as ...)` on the line after the import. TypeScript parses that `;` as the import statement's terminator, so replacing through `statement.getEnd()` deletes it and breaks ASI. The rewrite now stops at the module specifier. - A file that already imported directly from a module got a SECOND import from it, because the barrel re-exported those same names — which trips `import/no-duplicates` under `--deny-warnings`. A post-pass merges declarations sharing a specifier and type-only-ness; the `import type` plus `import` pair from one module is left alone, since that form is allowed. Splitting one barrel import into several genuinely adds lines, which pushed `terminal-layout-pty-ownership.ts` to 301 counted lines: its 107-character import must wrap, and neither local type collapses onto one line (101 and 116 characters). Rather than contort a type declaration to fit a line budget, `collectLeafIds` and `pruneLeaves` move to `terminal-pane-layout-tree.ts` — they are pure structural operations on the layout tree and independent of PTY ownership. `visible-worktrees.ts` similarly loses its own mini-barrel re-export of `isDefaultBranchWorkspace`, with the four real consumers repointed at the declaring module. No `max-lines` bypass added. Verified: cold `tsc --noEmit` green on node, cli, and web (buildinfo deleted first — these projects are `composite: true` and reuse stale caches); the full `pnpm lint` green, not just bare oxlint — the narrower local check is what let the duplicate imports reach CI; max-lines ratchet OK at 344. |
||
|
|
583ab1601b |
refactor(shared): group worktree, github, and linear modules into folders (#14437)
`src/shared` is a flat directory of ~1,150 entries. The worktree, github, and
linear domains accounted for 71 of them, so finding the module you wanted meant
scanning a wall of same-prefixed filenames.
Move each domain into its own folder and drop the now-redundant prefix:
src/shared/github-pr-types.ts -> src/shared/github/pull-request-types.ts
src/shared/worktree-id.ts -> src/shared/worktree/id.ts
src/shared/linear-links.ts -> src/shared/linear/links.ts
This follows the existing `network/` and `new-workspace/` convention in the
same directory, which also drop the prefix inside the folder.
Whole clusters move, including tests. Foldering only part of a domain would be
worse than flat: a reader would have to check both `github/` and the flat
directory, and `github-auth-types.ts` / `github-project-types.ts` are type
modules that belong with the rest. No files with these prefixes remain flat.
Import specifiers were rewritten by resolving each one to an absolute path and
recomputing it, not by string substitution, so the `@/../../shared/...` alias
forms are handled correctly. 501 specifiers across 298 files.
Two things `tsc` cannot catch, handled explicitly:
- `github-project-types.ts` carries its own `max-lines` bypass, so its baseline
entry is REPOINTED to the new path rather than pruned. Pruning would drop the
bypass and then flag the new path as a fresh violation. Ratchet stays at 345.
- `mobile/` is outside `pnpm typecheck` and cannot be typechecked here
(`mobile/node_modules` is empty). Instead every relative specifier in the repo
was resolved against the filesystem: 174 unresolved before this change and 174
after — identical, so nothing broke in mobile either.
The pinned `tests/e2e/.cross-version-checkouts` fixtures are deliberately NOT
rewritten; they are a snapshot of an older release and still reference the old
paths.
Verified: cold `tsc --noEmit` green on node, cli, and web (buildinfo deleted
first — these projects are `composite: true` and reuse stale caches).
|