Current behavior
TerraformResource.markWriteOnlyAttribute() at packages/cdktn/src/terraform-resource.ts:308 wraps a value in an IResolvable that, at resolve time, checks whether the resolved value is non-null before registering WRITE_ONLY_ATTRIBUTES usage:
if (resolved != null) {
resource._registerResolveDiscoveredProviderFeatureUsage(
ProviderFeature.WRITE_ONLY_ATTRIBUTES,
);
}
The != null (loose inequality) check correctly returns false for both null and undefined, so registration is suppressed for either.
What is currently tested
The test file packages/cdktn/test/write-only.test.ts covers:
- Literal
null — constructor and setter, with and without prior real values
- Literal
undefined — reset, omitted constructor arg
- Lazy resolving to
undefined — Lazy.stringValue({ produce: () => undefined })
- Real values — literal strings and Lazy resolving to strings
What is missing
Two null-equivalent value forms have no test coverage:
-
Token.nullValue() — the canonical public API for producing an explicit Terraform null:
public static nullValue(): IResolvable {
return Token.asAny(null); // wraps `null` in an `Intrinsic`
}
Intrinsic.resolve() returns null, and context.resolve(null) returns null, so the != null check correctly suppresses registration. But there is no test passing Token.nullValue() through markWriteOnlyAttribute. A future refactor that changed the check from != null to !== undefined would silently break this path.
-
Lazy.anyValue({ produce: () => null }) — a Lazy explicitly resolving to null (distinct from undefined). The existing Lazy test only covers undefined-producing Lazy. A null-producing Lazy renders as explicit null in Terraform (vs. omitted attribute for undefined), so it matters that the write-only guard suppresses validation for it.
How to fix
Add two test cases alongside the existing Lazy tests in write-only.test.ts:
test("Token.nullValue(): resolves to null, attribute renders as explicit null, synth passes", () => {
const { app, stack } = appWithStack();
const resource = new TestWriteOnlyResource(stack, "test", {});
resource.secretKeyWo = Token.nullValue() as unknown as string;
expect(synthesizedSecretKeyWo(stack)).toBeNull();
expect(() => app.synth()).not.toThrow();
});
test("Lazy producer resolving to null: attribute renders as explicit null, synth passes", () => {
const { app, stack } = appWithStack();
const resource = new TestWriteOnlyResource(stack, "test", {});
resource.secretKeyWo = Lazy.stringValue({ produce: () => null }) as unknown as string;
expect(synthesizedSecretKeyWo(stack)).toBeNull();
expect(() => app.synth()).not.toThrow();
});
Alternatively, widen the test resource setter to any | IResolvable | null to remove the need for casts.
Impact
Low risk, test-only change. No behavior change to production code — the existing != null check already handles these cases correctly. The fix confirms that the canonical null-token path stays covered against future null-check refactors.
Flagged during review of PR #296 by @so0k.
Current behavior
TerraformResource.markWriteOnlyAttribute()atpackages/cdktn/src/terraform-resource.ts:308wraps a value in anIResolvablethat, at resolve time, checks whether the resolved value is non-null before registeringWRITE_ONLY_ATTRIBUTESusage:The
!= null(loose inequality) check correctly returnsfalsefor bothnullandundefined, so registration is suppressed for either.What is currently tested
The test file
packages/cdktn/test/write-only.test.tscovers:null— constructor and setter, with and without prior real valuesundefined— reset, omitted constructor argundefined—Lazy.stringValue({ produce: () => undefined })What is missing
Two null-equivalent value forms have no test coverage:
Token.nullValue()— the canonical public API for producing an explicit Terraformnull:Intrinsic.resolve()returnsnull, andcontext.resolve(null)returnsnull, so the!= nullcheck correctly suppresses registration. But there is no test passingToken.nullValue()throughmarkWriteOnlyAttribute. A future refactor that changed the check from!= nullto!== undefinedwould silently break this path.Lazy.anyValue({ produce: () => null })— a Lazy explicitly resolving tonull(distinct fromundefined). The existing Lazy test only coversundefined-producing Lazy. Anull-producing Lazy renders as explicitnullin Terraform (vs. omitted attribute forundefined), so it matters that the write-only guard suppresses validation for it.How to fix
Add two test cases alongside the existing Lazy tests in
write-only.test.ts:Alternatively, widen the test resource setter to
any | IResolvable | nullto remove the need for casts.Impact
Low risk, test-only change. No behavior change to production code — the existing
!= nullcheck already handles these cases correctly. The fix confirms that the canonical null-token path stays covered against future null-check refactors.Flagged during review of PR #296 by @so0k.