feat(hooks): HooksManager orchestration and HooksParser validation (3/7) - #674
feat(hooks): HooksManager orchestration and HooksParser validation (3/7)#674gemammercado wants to merge 1 commit into
Conversation
Code Coverage OverviewLanguages: TypeScript TypeScript / code-coverage/vitestThe overall line coverage in commit 4a8b23b in the Show a line coverage summary of the most impacted files.
Updated |
26c4f14 to
58fe3b5
Compare
kddejong
left a comment
There was a problem hiding this comment.
Nice, well-scoped addition — strong input validation and sensible caching throughout. A few notes:
Suggested change before merge
Silent error swallowing in listHooksDetailed (HooksManager.ts)
try {
configuration = await this.hookCache.getConfiguration(...);
parsed = parseHookConfiguration(configuration);
} catch {
parsed = { configured: false }; // error discarded, no log
}A failed getHookConfiguration (e.g. an IAM permission error) is indistinguishable from a genuinely unconfigured hook — both surface as configured: false. That will make field debugging painful. Recommend logging the caught error at debug/warn before falling back.
Optional polish
describeHookhas no in-flight dedup. ConcurrentdescribeHookcalls for the same uncached key will each hitcfnService.describeHook.listHooksDetailedalready dedups configuration fetches viaHookCache; the same in-flight-promise pattern could be applied here if the LSP can issue concurrent describes..refine((data) => data.typeName ?? data.arn, ...)(Describe/Deactivate schemas) works becauseNonEmptyZodStringguarantees truthiness, butBoolean(data.typeName || data.arn)states the "at least one present" intent more clearly.CreateGuardHookParamsSchemavalidates required keys are present (obj[key] === undefined) but not that they're non-empty/typed — fine for a params-layer check, just confirming deeper validation happens downstream.
Strengths
.strict()on every schema rejects unknown keys — good hardening for LSP-facing input.- S3 bucket validation is genuinely thorough (length + consecutive-dot/dot-hyphen + IP-address-format rejection).
describeHookcaches results under bothtypeNameandarn, so subsequent lookups by either identifier hit cache.parseHookConfiguration/extractRuleUriare defensively written against malformed JSON and both string/objectruleLocationshapes.
The only blocking item is logging the swallowed error in listHooksDetailed; everything else is optional.
58fe3b5 to
4a8b23b
Compare
PR 3 of 7 — hook orchestration and request parsing (stacked)
Third slice of the CloudFormation Hooks feature, following #655 (cache infra) and #662 (AWS service layer), both merged. This adds the layer between the LSP handlers and the AWS services. Handlers and LSP wiring come in a later slice, so nothing here is reachable from the server yet.
What's in it
HooksManager— orchestrates hook listing and detail lookup on top ofCfnService:listHooks()starts a fresh page set;listHooks(true)appends the next page using the retainednextToken, deduplicating by type name. Requesting more when there is nonextTokenis a no-op that returns what is already cached rather than silently refetching page one.listHooksDetailed()enriches each listed hook with its type configuration. Fetches are batched at a concurrency of 10 so a large hook count cannot fan out into hundreds of simultaneous API calls. A configuration fetch that fails degrades that hook to "not configured" instead of failing the whole listing.describeHook()accepts either a type name or an ARN and caches the result under both identifiers, so looking a hook up one way and then the other does not trigger a second API call. Requesting neither identifier is rejected up front.getCachedRuleContent()reads Guard rule files through the TTLHookCachefrom feat(hooks): add TTL HookCache and persistent hook schema store #655, so repeated reads of the same S3 object do not re-download it.parseHookConfiguration()reads the nestedCloudFormationConfiguration.HookConfigurationwrapper and extracts failure mode, invocation status, target operations, and rule URI. Malformed JSON, a missing wrapper, or unexpected value types yield "not configured" rather than throwing.HooksParser— zod schemas that validate and narrow the parameters of every hook LSP request before they reach a handler, so malformed client input produces a clear validation error instead of a downstream failure. Includes a Guard-hook payload check that reports each missing required key.Testing
Unit tests for both files: pagination (including the no-more-pages case), deduplication, detail caching across both identifiers, the batching boundary with 25 hooks (asserting every hook resolves and peak concurrency stays within the limit), rule-content caching and loader error propagation, configuration parsing edge cases, and all parser schemas including malformed and missing input. Build, lint, and tests pass.
Stack
Base:
main(requires #655 and #662, both merged). Next slice: local Guard hook preview.