feat(protect): add unified logging filter sets (jamfprotect-go-sdk v0.8.0) - #317
Conversation
….8.0) Bump jamfprotect-go-sdk v0.7.1 -> v0.8.0 and wire in the three capabilities it introduces. New resource `protect unified-logging-filter-sets` (`ulfs`), modelled on `analytic-sets`: list/get/apply/delete/export plus idempotent read-modify-write `add-filter`/`remove-filter`. Export uses filter names rather than UUIDs so files stay portable across tenants; the server-side `plans` back-reference is excluded from the export format. Unified logging filters now surface their `sets` membership. `get`/`apply` move from `protect.PrintOne` to `printResult` so the nested array doesn't reach table output — this also brings ULF in line with the get/apply convention already documented in CLAUDE.md. Plans gain `unifiedLoggingFilterSets` in both the export format (name-based, resolved on apply) and the flattened table output. Verified end-to-end against a live tenant: full CRUD, granular mutations and their idempotency, name resolution, plan attach/detach, and the output/flag matrix from docs/solutions/conventions/output-flag-matrix. Two API behaviours confirmed by probe: the server refuses to delete a set still used by a plan, and deleting a filter cascades it out of any sets. Also records a conventions doc for a pre-existing behaviour found during cleanup: `protect apply` cannot clear a collection field, because an omitted key and an explicit `[]` produce the same request. It affects `exceptionSets` and `analyticSets` equally, so the new field matches that shape rather than diverging; the `remove-*` subcommands are the way to detach. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…cope flattenULF/flattenULFSet always emit their collection/detail keys now (uuid/description/tags for ULF, filters/plans for ULF sets) so table/csv/plain output has field-complete, row-stable columns instead of depending on the first row's data. CLAUDE.md and the collections-clearing solutions doc scoped their "apply cannot clear a collection" claim to plans apply's cross-resource references — it was stated as universal but ulfs/analytic-sets apply do clear their own membership list, which the new code correctly relies on. Added a matching --help warning on plans apply, and tests for the two resolver-calling paths (ulfSetExportToInput, planExportToInput's ULFSets branch) that a mutation pass found unverified. README alias table and the overview call count are updated to match. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
|
@ktn-jamf Addressed all three blocking findings plus the doc/README nice-to-haves:
Left (5) — the resolver-error/not-found conflation in
|
…317 re-review - flattenPlan always emits unifiedLoggingFilterSets so -o table/csv columns don't disappear when the first plan in the result has no sets attached - flattenULFSet surfaces uuid, matching the sibling flattenULF Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
Round 3 fixes pushed (
|
ktn-jamf
left a comment
There was a problem hiding this comment.
Tip
✅ Merge-ready — Adds protect unified-logging-filter-sets (ulfs) plus the jamfprotect-go-sdk v0.8.0 bump, surfacing sets/unifiedLoggingFilterSets back-references on ULF and plans. All findings from rounds 1 and 2 are fixed.
Rating: 5/5
- Clean — the fix commit (
fb6b6ca) closes round 2's one blocking finding and its uuid nice-to-have with no regressions; the two remaining nice-to-haves are author-acknowledged, package-wide follow-ups, not defects in this PR.
Prior review status
Round 1 (5d8d912): 3 blocking findings (stale doc scope, flattenULF dropped fields, row-0 column instability) + 3 nice-to-have — all fixed in 216baa7. Round 2 (bae861f): 1 new blocking finding (flattenPlan reintroduced the same row-0 bug) + 1 actionable nice-to-have (flattenULFSet missing uuid) — both fixed in fb6b6ca, verified below. The two reliability nice-to-haves from round 2 (lost-update race on add-filter/remove-filter; nil-response panic after concurrent delete) remain 💬 Dismissed — author left them as package-wide follow-ups matching the identical pattern in every sibling apply/Get*, which the round-2 review agreed avoids diverging the fix from the rest of the package.
What's done well
✅ Three rounds in, the fix commits stay disciplined rather than papering over findings. fb6b6ca applies the exact // always present: table/csv columns come from row 0 fix to flattenPlan that rounds 1's fix already proved out on flattenULF/flattenULFSet, with the test assertion inverted the same way (TestFlattenPlan_EmptyUnifiedLoggingFilterSetsPresent). No shortcut, no new pattern — the third sibling now matches the other two exactly.
Review coverage
- Design and architecture:
fb6b6caedextends the already-vettedanalytic-sets/flattenULFpattern toflattenPlan; no divergence, no new abstraction - Correctness: traced
flattenPlan's unconditionalunifiedLoggingFilterSetsassignment throughprintTable/printCSV/printPlain's row-0 column derivation (internal/output/output.go) — confirmed the column no longer disappears when the first plan has no sets; confirmedflattenULFSet's newuuidfield matches the siblingflattenULF - Security: no new surface in the fix commit; SDK boundary was already resolved at source in rounds 1–2 (
jamfprotect-go-sdk@v0.8.0module cache read directly) - [na] Performance: no DB/query/cache/hot-path files touched by the fix commit or the whole-PR diff
- Test coverage:
TestFlattenPlan_EmptyUnifiedLoggingFilterSetsPresentand theuuidassertion inTestFlattenULFSet_FiltersAndPlansverified against the code change;go test ./internal/commands/... ./internal/protect/...green at current head (47d7acc) - Reliability: the two dismissed nice-to-haves (lost-update race, nil-response panic) remain open only as cross-package follow-ups, unchanged in shape from round 2
- Code quality: fix commit's comment style and naming match the established convention
- [na] Simplification: no new abstraction introduced by the fix commit
- [na] Frontend concerns: no UI in this repo
- Documentation currency: re-verified
CLAUDE.md:283("Protectoverviewmakes ~17") andREADME.md:227(ulfsalias row) both still match current code - Cross-repo contracts: no new SDK surface touched since round 2's source-level verification
- Project rules compliance: no
.claude/rules/directory; fix commit adds no credential flags, touches no generated code
Scope of review
- This round's diff: whole-PR diff unchanged since round 2 except the fix commit
fb6b6caed(3 files, +15/−9) plus an interveningmain-merge commit (47d7accd7) that pulls in unrelated changes now onmain(PR #316/#318) — confirmed not part of this PR's contribution viagit diff --stat origin/main...origin/feat/protect-unified-logging-filter-sets, which still shows the original 18 files / 1017+/13− against currentmain. - Fix commit read in full (
git show fb6b6caed) and independently traced againstinternal/output/output.go's row-0 derivation, rather than taken on the author's description. - Build and tests re-run at current head (
47d7acc):go build ./...clean;go test ./internal/commands/... ./internal/protect/...green. - Specialists not re-dispatched this round. All 4 eligible lanes (
security-reviewer,usability-reviewer,devil-advocate,test-quality-reviewer) are already ineverfrom rounds 1–2. The fix commit introduces no new high-risk-regardless-of-size shape — the removedif len() > 0is a display-formatting guard (which map key exists for table/csv output), not a security, auth, or business-logic branch, and it's a mechanical repeat of the identical guard already removed (and specialist-reviewed) inflattenULF/flattenULFSetduring round 1. Per the "lane already inever" rule, re-spawning is warranted only for new high-risk changes; none are present. - Never-run lanes (unchanged from rounds 1–2):
performance-reviewer— no DB/query/cache/hot-path files;scope-reviewer— single-concern change;fidelity-reviewer— no linked ticket/issue/branch-name key.
Generated by pr-review v1.29.0, a Jamf Claude Code skill
What
Bumps
jamfprotect-go-sdkv0.7.1 → v0.8.0 and adds CLI support for the three capabilities that release introduces.UnifiedLoggingFilterSet(full CRUD + list)protect unified-logging-filter-sets(ulfs)UnifiedLoggingFilter.setsback-referenceulf list/getoutputPlan.unifiedLoggingFilterSets+PlanInputplansexport/apply + flattened outputA filter set groups unified logging filters so they can be assigned to a plan as a unit — the ULF analogue of
analytic-sets, and modelled on it directly.Commands
applyupserts by name,add-filter/remove-filterare idempotent read-modify-write,deletecarriesjamf:destructive.exportuses filter names rather than UUIDs so files stay portable across tenants, and deliberately omits the server-sideplansback-reference.Attach to a plan by name:
Notable
ULF
get/applymoved fromprotect.PrintOnetoprintResult. The filter now carries a nestedsetsarray, which renders badly in table output. This also brings ULF in line with theget/applyconvention CLAUDE.md already documents, so it's a drive-by consistency fix rather than a new pattern.SDK moved ULF operations from
/graphqlto/app. Worth knowing that the two endpoints serve different schemas —updatePlandoesn't exist on/graphqlat all. Verified reads and mutations both work on the new path.Verification
Exercised end-to-end against a live sandbox tenant, then cleaned up — full CRUD, granular mutation idempotency, name resolution, plan attach/detach, and the complete flag matrix from
docs/solutions/conventions/output-flag-matrix(json/yaml/csv/plain/table,--field,--select,--compact,--quiet,NO_COLOR=1,--out-file).Two API behaviours confirmed by probe, both handled by clear server-side errors rather than client guards:
16 new tests, all green (
go test ./...exit 0, 28 packages),make lint0 issues,verify-generatedandverify-sitepass. Coverage spans the conversion/flatten functions (including empty-collection omission), resolver found/not-found/caching, and the structural allowlists inprotect_test.gothat verify wiring. The wiring tests were mutation-checked: unwiringAddCommandfails all three.Pre-existing limitation documented, not changed
While cleaning up I found that
protect applycannot clear a collection field —if len(x) > 0plus the SDK's nil check means an omitted key and an explicit[]produce the same request, so the server keeps its existing membership. This affectsexceptionSetsandanalyticSetsidentically; it is not new here.I made the new field match that shape rather than diverge, since two collections on the same input behaving differently would be worse than a uniform documented limitation, and the
remove-*subcommands already cover the real use case. Written up indocs/solutions/conventions/protect-apply-cannot-clear-collections-2026-08-07.mdwith the shape a proper fix would need.Happy to make
applyclear-capable across all collection fields as a follow-up if you'd rather — it needs*[]string(or raw-map key presence) plus a matching SDK change.🤖 Generated with Claude Code