feat: TideError sweep, error-reporting v1, reservation ProblemDetails fix#77
Open
DomValladolid wants to merge 34 commits into
Open
feat: TideError sweep, error-reporting v1, reservation ProblemDetails fix#77DomValladolid wants to merge 34 commits into
DomValladolid wants to merge 34 commits into
Conversation
Policiessss
improvements + fixes
New custom sign request
Release release/0.13.1
Release 0.13.11
Release 0.13.21
Release 0.13.26
Release 0.13.27
Release 0.13.28
Release 0.13.30
Release 0.13.31
For the SWE error-reporting initiative: - Upgrade 81 raw throw Error() sites in Cryptide/Components, TideKey, AES, DH, Serialization, Doken, TideMemoryObjects, Tools/TideMemory to structured TideError under new CRYPTO_/SERIAL_/MODEL_/MEM_ code families - Add Clients/RecentRequestsBuffer for SWE error-report context (FIFO bounded ring, in-memory only, no payloads) - Auto-push entries from ClientBase._get/_post/_put/_postJSON with performance.now() timing - Add tideJsVersion placeholder export for build correlation - 21 new error code constants in Errors/codes.ts All displayMessages carry only metadata (lengths, offsets, type names); zero key bytes / ciphertext / plaintext. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Independent security review found that buildReportPayload.js in the ORK
Enclave does `import { TideError } from "@tideorg/js"` (named import),
but tide-js/index.ts only exposed TideError via the `Errors` namespace
(`export * as Errors from './Errors'`). The named import resolved to
undefined, so TideError.isTideError(error) crashed on first error
modal open.
Add top-level re-exports of TideError, TideJsErrorCodes,
RecentRequestsBuffer + their accompanying types. Preserves the existing
`Errors` namespace export (keycloak-IGA consumes Errors.TideError per
the Phase 1 audit comments).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Converts 20 raw `throw Error(...)` sites in BaseScheme + Ed25519 component classes + Ed25519 scheme functions to TideError, plus adds 11 new code constants in Errors/codes.ts used by the rest of the v1.1 sweep: CRYPTO_ED25519_BAD_POINT, CRYPTO_INVERSE_NOT_EXIST, CRYPTO_INVALID_BIGINT_INPUT, CRYPTO_HASH_TO_POINT_INVALID_INPUT, SIG_VERIFY_FAILED, MODEL_UNKNOWN_MODEL, MODEL_UNKNOWN_PARAM_TYPE, MODEL_PARAM_NOT_FOUND, MODEL_DEV_ERROR, MODEL_REQUEST_NOT_INITIALIZED, MODEL_VERSION_MISMATCH Site → code assignments (curve-scheme tier): - BaseScheme.ts:22-25 (x4) → CRYPTO_NOT_IMPLEMENTED - Ed25519Components.ts:42 → SERIAL_INVALID_TYPE - Ed25519Components.ts:46 → MODEL_INVALID_FIELD - Ed25519Components.ts:52 → MODEL_INVALID_FIELD - Ed25519Components.ts:60 → CRYPTO_COMPONENT_MISMATCH (Add) - Ed25519Components.ts:66 → CRYPTO_COMPONENT_MISMATCH (Multiply) - Ed25519Components.ts:72 → CRYPTO_COMPONENT_MISMATCH (Minus) - Ed25519Components.ts:78 → CRYPTO_COMPONENT_MISMATCH (Equals) - Ed25519Components.ts:98 → MODEL_INVALID_FIELD (private.priv) - Ed25519Components.ts:104 → MODEL_INVALID_FIELD (private.rawBytes) - Ed25519Components.ts:114 → SERIAL_INVALID_TYPE (private ctor) - Ed25519Components.ts:144 → SERIAL_INVALID_TYPE (seed ctor) - Ed25519Scheme.ts:36 → SERIAL_INVALID_TYPE (sign type) - Ed25519Scheme.ts:44 → SIG_VERIFY_FAILED - Ed25519Scheme.ts:46 → SERIAL_INVALID_TYPE (verify type) - Ed25519Scheme.ts:55 → SERIAL_INVALID_TYPE (encrypt type) - Ed25519Scheme.ts:64 → SERIAL_INVALID_TYPE (decrypt type) Follows v1 conventions documented in commit 665677f-style (structured fields, no banned-token leakage - displayMessages carry only metadata, never raw key bytes or component contents). Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Converts 13 raw `throw Error(...)` sites in the low-level math
and Ed25519 primitives to TideError:
- Interpolation.ts:46 → CRYPTO_ORK_ARRAY_LENGTH_MISMATCH
- Interpolation.ts:55 → CRYPTO_ORK_ARRAY_LENGTH_MISMATCH
- Math.ts:77 → CRYPTO_INVERSE_NOT_EXIST (mod_inv zero/neg)
- Math.ts:92 → CRYPTO_INVERSE_NOT_EXIST (gcd != 1)
- Ed25519.ts:63 → CRYPTO_ED25519_BAD_POINT (err helper, routes
~15 internal `err(...)` callsites through TideError)
- Ed25519.ts:133 → CRYPTO_ED25519_BAD_POINT (bad point: ZERO)
- Ed25519.ts:145 → CRYPTO_ED25519_BAD_POINT (left != right (1))
- Ed25519.ts:150 → CRYPTO_ED25519_BAD_POINT (left != right (2))
- Ed25519.ts:295 → CRYPTO_INVALID_BIGINT_INPUT (invert typeof)
- H2P.ts:82 → CRYPTO_HASH_TO_POINT_INVALID_INPUT (negative power)
- H2P.ts:166 → CRYPTO_HASH_TO_POINT_INVALID_INPUT (i2osp range)
- H2P.ts:188 → CRYPTO_HASH_TO_POINT_INVALID_INPUT (xmd length)
- TideSignature.ts:35 → SERIAL_INVALID_TYPE
Sanitisation: Math.ts:77 and Ed25519.ts:297 originally embedded
the raw `number`/`num` bigint (which can be a private scalar)
into displayMessage. Replaced with sign-only metadata
("zero" / "non-zero", "non-positive" / "positive").
Follows v1 conventions documented in commit 665677f-style
(structured fields, cause-chain, no banned-token leakage -
buildReportPayload.test.js still passes).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Converts 16 raw `throw Error(...)` sites in the Models tier to TideError, completing the Models-side coverage so all request construction / Policy parsing flows surface structured errors: - ModelRegistry.ts:34 → MODEL_UNKNOWN_MODEL - BaseTideRequest.ts:174 → MODEL_REQUEST_NOT_INITIALIZED (addApproval) - BaseTideRequest.ts:246 → MODEL_REQUEST_NOT_INITIALIZED (encode authorizer) - BaseTideRequest.ts:247 → MODEL_REQUEST_NOT_INITIALIZED (encode authorizerCert) - BaseTideRequest.ts:248 → MODEL_REQUEST_NOT_INITIALIZED (encode authorization) - BaseTideRequest.ts:287 → MODEL_INVALID_FIELD (decode name/version) - BaseTideRequest.ts:332 → SERIAL_INVALID_LENGTH (uint8ArrayToUint32LE) - Policy.ts:75 → MODEL_VERSION_MISMATCH (unknown version) - Policy.ts:176 → MODEL_UNKNOWN_PARAM_TYPE (fromBytes) - Policy.ts:195 → MODEL_PARAM_NOT_FOUND - Policy.ts:219 → MODEL_INVALID_FIELD (unexpected param type) - Policy.ts:253 → MODEL_UNKNOWN_PARAM_TYPE (toBytes) - Policy.ts:273 → MODEL_DEV_ERROR (PolicyV2 version assertion) - Policy.ts:325 → MODEL_DEV_ERROR (PolicyV1 version assertion) - SerializedField.ts:41 → MODEL_VERSION_MISMATCH - PolicyProtectedSerializedField.ts:41 → MODEL_VERSION_MISMATCH `throw 'string'` literals in Policy.ts ctor (lines 26/30/36/38/40/46) are intentionally OUT of scope - they aren't `throw new Error(...)` sites and the parking-lot covers `throw Error` only. Tracked for v1.2 follow-up. Follows v1 conventions documented in commit 665677f-style (structured fields, cause-chain, no banned-token leakage - buildReportPayload.test.js still passes). Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Converts the 1 raw `throw Error(...)` site in removeRandomElements to TideError: - Tools/Utils.ts:262 → SERIAL_INVALID_LENGTH Follows v1 conventions documented in commit 665677f-style (structured fields, no banned-token leakage - displayMessage carries only array-length metadata). Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…roblem+json pass-through ORKs emit PascalCase ProblemDetails fields (Code/MessageKey/MessageParams/...) on the wire, but _handleError only read lowercase, so every ORK problem+json degraded to PARSE_PROBLEM_JSON_INVALID. Extract the problem+json branch into _problemDetailsToError, which reads each envelope field case-tolerantly (lowercase preferred for back-compat, PascalCase canonical going forward). messageParams dictionary KEYS pass through untouched; messageKey is copied verbatim with no prefix assumptions. Also wire the helper into _get and _getSilent: previously they threw NET_NON_OK_STATUS before reading the body, so structured 409s (e.g. TIDE-ORK-KEYGEN-USERNAME_RESERVED from GetReservers) were discarded. Non- problem+json non-ok responses keep the exact NET_NON_OK_STATUS behaviour. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Add WaitForORKsOptions bag to WaitForNumberofORKs (no 9th positional) with promoteUnanimousCodes (default off), threaded into PromiseRace. When the threshold fails and every per-ORK failure is a TideError sharing one identical non-TIDE-TIDEJS-* code, throw a promoted TideError carrying the upstream code/messageKey/messageParams/httpStatus/problemType/traceId instead of the generic NET_THRESHOLD_FAILURE. Representative failure is the one with the largest Number(messageParams.expirySeconds) (wire values are strings); falls back to failed[0] when absent/NaN. The promotion sits AFTER the 'Too many attempts' special case (admin-ui string-matches it) and BEFORE the generic threshold throw; behaviour is byte-identical for all callers with the flag off or non-unanimous failures. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Add Tests/ReservationErrors.test.mjs (node:test against compiled dist/) covering: PascalCase + lowercase ProblemDetails parsing, malformed-body fallback to PARSE_PROBLEM_JSON_INVALID, _get/_getSilent 409 problem+json pass-through vs NET_NON_OK_STATUS for non-problem bodies, and PromiseRace unanimous-code promotion (representative selection, mixed codes, transport codes, flag off). The repo had no automated test runner (Tests/ were manual browser pages, npm test was a stub). Wire 'npm test' to clean-build via tsc then run node --test with a small ESM resolver hook (node-esm-extension-loader.mjs) that appends .js to the extensionless relative specifiers tsc emits under moduleResolution: bundler. dist clean is required because rebuilding over an existing dist fails with TS5055 (pre-existing, reproduced on staging). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Phase 4 security-review fixes for the reservation error surfacing work:
- F1 true-unanimity gate: promotion now requires the failure set to cover
the FULL attempted cohort (failed.length === initLength, zero successes).
A timeout-truncated set falls through to NET_THRESHOLD_FAILURE, so one
fast malicious ORK + slow honest ORKs can no longer fake unanimity.
- F2 median representative: representative = median of numeric
messageParams.minutes (lower median on even counts), falling back to
median expirySeconds (older ORKs), then failed[0]. Non-finite values
("9e999", "Infinity", "NaN") are never candidates, so a single cohort
member cannot control the displayed fields.
- F3 ProblemDetails field validation (all problem+json paths): envelope
fields must be strings or are dropped; code/messageKey <= 256 chars with
charset [A-Za-z0-9._:-] (dropped on failure, never thrown); detail/title
truncated to 2048; traceId/source/type/instance truncated to 256;
messageParams must be a plain object, <= 16 keys matching
^[A-Za-z0-9_]{1,64}$ (prototype-polluting names dropped), values
String()-coerced and truncated to 256.
- F4 promoted-messageKey namespace guard: a promoted error carries
messageKey only if it starts with error.tide. / errors.tide. — blocks
arbitrary i18n-catalog key selection through the promotion path.
- F5 tests: 16 new cases (partial-set no-promote, median/outlier/non-finite
selection, drop/truncate without throwing incl. __proto__ and 1MB bodies,
namespace guard); 29 total passing.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
This PR brings the following completed initiatives from
stagingintomain-merge:TideErrorsweep across Cryptide, Models, Tools, and Clients tiers (81 rawthrow Error(...)converted to structuredTideErrorunderCRYPTO_*/SERIAL_*/MODEL_*/MEM_*code families). NewRecentRequestsBufferfor recent-request metadata. Top-level re-exports for ORK SWE consumption.ProblemDetailsparsing inClientBase(fixes silent degradation of every ORK problem+json toPARSE_PROBLEM_JSON_INVALID). Opt-in unanimous-code promotion inWaitForNumberofORKs(promoteUnanimousCodes: true) so cohort 409s surface the real code. Security hardening: true-unanimity gate, median representative selection, full field sanitization, promoted-messageKey namespace guard.Test plan
TideErrorstructured errors propagate from Cryptide operationsTIDE-ORK-KEYGEN-USERNAME_TAKENorUSERNAME_RESERVEDnpm testpasses (29 reservation + 69 buildReportPayload tests)🤖 Generated with Claude Code