Repository navigation
fix: test-infra and logger/config safety (#87, #88, #89, #90) - #94
Merged
Merged
Conversation
- #87 CI now typechecks test/ too via tsconfig.test.json. Previously no type error in any test file was visible to tsc or CI — how a TS2322 in a test went unnoticed. The override restates include AND exclude (the base config excludes test/, which would otherwise silently override include), sets rootDir "." (base sets rootDir "src", which trips TS6059) and noEmit, so it cannot dump dist/src + dist/test over the build layout if someone drops the flag. Verified by injecting a type error into a test file and watching the new step fail. Adds `npm run typecheck`, which is what CI runs and what the contributor docs now point at. - #88 logger.ts redaction widened to authorization/bearer/api-key/ credentials/passwd/cookie spellings and made recursive: sensitive keys are redacted at any depth through objects and arrays. Cycles terminate as [CIRCULAR], a shared (non-cycle) reference renders once per occurrence, and the ways a value can evade the walk are closed: - an inherited toJSON is replaced — a #private-field class whose toJSON returns its secret has no own keys, so JSON.stringify would invoke it after redaction; - a throwing getter, a throwing ownKeys trap, and a throwing toJSON getter each yield [UNREADABLE] rather than propagating out of warn(), which matters because warn() is called from error handlers; - nesting past 100 levels yields [MAX_DEPTH] rather than a RangeError; - a bare typed array has no toJSON, so JSON.stringify would emit every own property: its indices pass through but a NON-index key attached to it is redacted like any other field; - a payload JSON.stringify rejects (BigInt) degrades to log_stringify_error while KEEPING ts/level/msg, because a bare error flag with no level and no message is untriageable; - a container-shaped value that reduces to a marker string is coerced back to an object, so it cannot be spread into a character map. Plus the module's first direct tests. Key-name matching remains best-effort, and the legacy log() helper takes positional args rather than a fields object so it does not redact at all. Both are now stated in USER-GUIDE instead of being implied away. - #89 first direct coverage for src/config.ts: required-var errors, safety-relevant defaults, LOG_FORMAT fallback, CUSTOMCONNSTR_ fallback, and the CARELINK_QUIET truthiness table pinned as current behaviour. The env scrub is case-insensitive over every prefix readEnv honours (lowercase keys included), so an ambient MMCONNECT_COUNTRYCODE cannot break the safety-default assertions. USER-GUIDE and .env.example now state the coercion: only the literal "false" enables verbose mode. - #90 documented that verbose mode logs the full upload payload, in the CARELINK_QUIET and LOG_FORMAT rows and on upload() itself. - Docs corrected rather than left absolute: "secrets are never emitted" (USER-GUIDE), "no PII" (ARCHITECTURE module map), and the `npx tsc --noEmit` verification step in ARCHITECTURE + CONTRIBUTING. Tests: 288 passing (baseline 246). `npm run typecheck` clean.
This was referenced Oct 9, 2026
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
Four small safety fixes to the test infrastructure and the logger/config layer, found by auditing the bridge against Medtronic's live API behaviour.
npx tsc --noEmitreads the basetsconfig.json, which excludestest/. A TS2322 in a test compiled clean and CI stayed green. Addedtsconfig.test.json, atypecheckscript that runs both configs, and pointed CI and the contributor docs at it.Authorizationand nested objects. The regex matched onlysecret|password|token|api_secret, andredactFieldswas a flat loop, so{headers:{Authorization}}logged in clear. Widened the pattern, made the walk recursive, and gave the module its first direct tests.src/config.tshad zero coverage. Added tests for required-var errors, safety-relevant defaults,LOG_FORMATfallback and theCUSTOMCONNSTR_fallback, and documented theCARELINK_QUIETcoercion trap: only the literalfalseenables verbose mode, so0,noandyesall mean quiet and an empty value counts as unset.upload()itself rather than left to be discovered.Also corrected four docs that overstated what the code does — the "secrets are never emitted" line in USER-GUIDE, "no PII" in the ARCHITECTURE module map, and the
npx tsc --noEmitverification step in ARCHITECTURE and CONTRIBUTING.Verification
The new CI step is proven, not assumed: injecting
const x: number = "nope"into a test file makes it fail with TS2322 while the old command still exits 0. Each redaction guard has a matching test, and reverting any one of them fails the suite. The redaction walk was audited against class instances, cross-realm objects, inherited and owntoJSON, throwing getters andownKeystraps, circular and shared references,__proto__keys, typed arrays with attached fields, BigInt, 50 000-deep nesting and Proxy traps — nothing leaks andwarn()never throws into its caller, which matters because it is called from error handlers.Notes
Redaction is key-name matching, not content inspection, and the legacy
log()helper takes positional arguments rather than a fields object so it does not redact at all. Both limits are now stated in USER-GUIDE instead of being implied away — a logger that claims more than it does is worse than one that doesn't.Closes #87, #88, #89, #90.