Skip to content

[codex] Validate affiliate offer tag types#419

Merged
ralyodio merged 1 commit into
profullstack:masterfrom
jsdavid278-cyber:codex/ugig-affiliate-tags-type
Jun 6, 2026
Merged

[codex] Validate affiliate offer tag types#419
ralyodio merged 1 commit into
profullstack:masterfrom
jsdavid278-cyber:codex/ugig-affiliate-tags-type

Conversation

@jsdavid278-cyber
Copy link
Copy Markdown
Contributor

Summary

  • reject non-array tags values during affiliate offer validation
  • reject non-string tag entries before sanitizing with .trim().toLowerCase()
  • add a regression test for tags: ["valid", 123]

Fixes #418.

Validation

  • npm.cmd run test:run -- src/lib/affiliates/validation.test.ts
  • npm.cmd run type-check

@greptile-apps
Copy link
Copy Markdown

greptile-apps Bot commented Jun 6, 2026

Greptile Summary

This PR hardens affiliate offer tag validation by rejecting non-array tags inputs and non-string tag entries before the .trim().toLowerCase() sanitization step, accompanied by a regression test for a mixed-type array.

  • validation.ts: the old truthy guard (if (input.tags && ...)) is replaced with an explicit !== undefined check plus Array.isArray and typeof guards, but this silently changes behavior for null tags — previously accepted, now rejected as "not an array."
  • validation.test.ts: one new test covers [\"valid\", 123]; the fully non-array case (e.g. tags: \"string\" or tags: null) has no test, leaving the new !Array.isArray branch unverified.

Confidence Score: 3/5

Safe to merge only after confirming whether null tags can arrive from the database or API; if they can, the guard change will start rejecting previously-valid updates.

The core logic protecting .trim().toLowerCase() from crashing on non-strings is correct, and the test for mixed-type arrays is a useful regression. However, swapping the old truthy check for !== undefined introduces an unintended behavior change: null tags now produce a validation error instead of being silently skipped. The sanitization path already handles null gracefully via optional chaining, making this inconsistency easy to overlook. There is also no test exercising the new !Array.isArray branch directly, so neither the null case nor a fully non-array input is verified.

src/lib/affiliates/validation.ts — the null-tags guard; src/lib/affiliates/validation.test.ts — missing coverage for non-array inputs

Important Files Changed

Filename Overview
src/lib/affiliates/validation.ts Adds non-array and non-string tag checks; the guard uses !== undefined rather than != null, inadvertently rejecting null tags that were previously accepted
src/lib/affiliates/validation.test.ts Adds one regression test for a mixed-type array; missing coverage for fully non-array tags values and the null case

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[validateOfferInput called] --> B{input.tags !== undefined?}
    B -- No --> Z[skip tags validation]
    B -- Yes --> C{Array.isArray?}
    C -- No --> D[push 'tags must be an array']
    C -- Yes --> E{length > 10?}
    E -- Yes --> F[push 'Maximum 10 tags']
    E -- No --> G{any tag typeof !== 'string'?}
    F --> G
    G -- Yes --> H[push 'tags must be strings']
    G -- No --> I{errors.length > 0?}
    H --> I
    D --> I
    I -- Yes --> J[return ok:false]
    I -- No --> K["sanitized: tags.map(t => t.trim().toLowerCase()).filter(Boolean)"]
    K --> L[return ok:true]

    style D fill:#f99,stroke:#c00
    style H fill:#f99,stroke:#c00
    style B fill:#ffe,stroke:#aa0
Loading

Reviews (1): Last reviewed commit: "fix: validate affiliate offer tag types" | Re-trigger Greptile

Comment on lines +124 to 135
if (input.tags !== undefined) {
if (!Array.isArray(input.tags)) {
errors.push("tags must be an array");
} else {
if (input.tags.length > 10) {
errors.push("Maximum 10 tags");
}
if (input.tags.some((tag) => typeof tag !== "string")) {
errors.push("tags must be strings");
}
}
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 null tags now rejected as a non-array

The guard changed from if (input.tags && ...) (truthy check) to if (input.tags !== undefined), so a null value now enters the branch and triggers "tags must be an array". null is a realistic runtime value: JSON round-trips, database reads, or existing API callers may pass tags: null when no tags are set. Previously that was silently accepted; now it becomes a validation error that breaks those callers. The sanitization path at line 153 already handles null correctly via optional chaining (input.tags?.map(...) || []), making this inconsistency easy to miss. Consider using input.tags != null (loose inequality) or explicitly handling the null case alongside undefined to preserve the prior behavior.

Comment on lines +173 to +180
it("rejects non-string tags before sanitizing", () => {
const result = validateOfferInput({
...validInput,
tags: ["valid", 123] as any,
});
expect(result.ok).toBe(false);
expect(result.errors.some((e) => e.includes("tags") && e.includes("strings"))).toBe(true);
});
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 No test for non-array tags value

The PR description says "reject non-array tags values," but the only new test uses an array that contains a non-string element (["valid", 123]). There is no test for the fully non-array case (e.g., tags: "string", tags: 42, or tags: null), leaving the new !Array.isArray(input.tags) branch untested. A test for tags: "not-an-array" would directly exercise the new guard and would also surface the null behavior described in the companion comment.

@ralyodio ralyodio merged commit 64e3fab into profullstack:master Jun 6, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Affiliate offer validation throws on non-string tags

2 participants