Skip to content

feat: config properties table#1955

Open
adityathebe wants to merge 3 commits into
mainfrom
feat/config-properties-normalized
Open

feat: config properties table#1955
adityathebe wants to merge 3 commits into
mainfrom
feat/config-properties-normalized

Conversation

@adityathebe
Copy link
Copy Markdown
Member

@adityathebe adityathebe commented May 5, 2026

Summary by CodeRabbit

  • New Features
    • Configuration items can now store typed, metadata-rich properties (labels, tooltips, icons, type, color, display order, flags, values, ranges, and optional links).
    • Properties are exposed in enriched/compatible views so existing APIs receive merged property arrays and extracted value fields.
    • Row-level security policies now govern access to configuration properties.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 5, 2026

Review Change Stack
No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: a6791fe4-f975-45b1-baf8-30321998590d

📥 Commits

Reviewing files that changed from the base of the PR and between 1683ff4 and 0c52d93.

📒 Files selected for processing (7)
  • models/config.go
  • rbac/objects.go
  • schema/config.hcl
  • views/006_config_views.sql
  • views/038_config_access.sql
  • views/9998_rls_enable.sql
  • views/9999_rls_disable.sql
✅ Files skipped from review due to trivial changes (1)
  • views/038_config_access.sql
🚧 Files skipped from review as they are similar to previous changes (6)
  • views/9998_rls_enable.sql
  • views/006_config_views.sql
  • rbac/objects.go
  • schema/config.hcl
  • models/config.go
  • views/9999_rls_disable.sql

Walkthrough

Added a new config_properties database table to store typed properties for config items, implemented corresponding API model with serialization methods, created views to aggregate properties into JSON form and enrich config items, configured RBAC and RLS access controls, and updated existing views to surface the new property data.

Changes

Config Properties Feature

Layer / File(s) Summary
Database Schema
schema/config.hcl
New config_properties table with id, config_id, scraper_id, created_by, and value/metadata fields; indexes, conditional unique indexes, and check constraint enforcing exactly one of scraper_id or created_by.
View Aggregation
views/006_config_views.sql
New config_properties_json view aggregates properties per config_id. New config_items_with_properties view joins config items with aggregated properties and computes properties_values. Updated configs and config_detail to source from config_items_with_properties.
API Model
models/config.go
New ConfigProperty struct with display/type/value/range/link fields. Added TableName(), NewConfigProperty() constructor from types.Property, and AsProperty() conversion back to types.Property.
Access Control (RBAC)
rbac/objects.go
Added RBAC table-to-object mappings for config_properties, config_properties_json, and config_items_with_properties to policy.ObjectCatalog.
Security Policies (RLS)
views/9998_rls_enable.sql, views/9999_rls_disable.sql
Enable RLS on config_properties and add config_properties_auth policy for postgrest_api/postgrest_anon; add conditional disable and policy cleanup. Set security_invoker = true on new views.
Maintenance
views/038_config_access.sql
Added an extra DROP VIEW IF EXISTS external_group_summary; before recreating config access summary views.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately and concisely summarizes the main change: introducing a new config_properties table with supporting models, views, and RBAC mappings.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/config-properties-normalized
✨ Simplify code
  • Create PR with simplified code
  • Commit simplified code in branch feat/config-properties-normalized

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 5, 2026

Benchstat (RLS)

Base: 617b11d4451d2f93ce8aa22f89b34eebcdc8686d
Head: 0c52d9349ec8065be23df000780b497275c53c90

📊 4 minor regression(s) (all within 5% threshold)

Benchmark Base Head Change p-value
RLS/Sample-15000/configs/With_RLS-4 135.7m 137.7m +1.45% 0.002
RLS/Sample-15000/change_types/Without_RLS-4 5.310m 5.385m +1.42% 0.009
RLS/Sample-15000/config_classes/With_RLS-4 135.1m 136.5m +1.06% 0.002
RLS/Sample-15000/config_names/With_RLS-4 139.0m 139.9m +0.62% 0.004
✅ 3 improvement(s)
Benchmark Base Head Change p-value
RLS/Sample-15000/change_types/With_RLS-4 5.544m 5.275m -4.86% 0.002
RLS/Sample-15000/config_detail/With_RLS-4 138.1m 135.9m -1.55% 0.002
RLS/Sample-15000/analysis_types/With_RLS-4 3.931m 3.904m -0.68% 0.041
Full benchstat output
goos: linux
goarch: amd64
pkg: github.com/flanksource/duty/bench
cpu: AMD EPYC 7763 64-Core Processor                
                                               │ bench-base.txt │           bench-head.txt           │
                                               │     sec/op     │    sec/op     vs base              │
RLS/Sample-15000/catalog_changes/Without_RLS-4      5.328m ± 3%    5.282m ± 1%       ~ (p=0.093 n=6)
RLS/Sample-15000/catalog_changes/With_RLS-4         143.3m ± 0%    142.9m ± 1%       ~ (p=0.180 n=6)
RLS/Sample-15000/config_changes/Without_RLS-4       5.409m ± 0%    5.305m ± 3%       ~ (p=0.065 n=6)
RLS/Sample-15000/config_changes/With_RLS-4          141.5m ± 0%    141.9m ± 1%       ~ (p=0.310 n=6)
RLS/Sample-15000/config_detail/Without_RLS-4        4.818m ± 1%    4.793m ± 2%       ~ (p=0.937 n=6)
RLS/Sample-15000/config_detail/With_RLS-4           138.1m ± 0%    135.9m ± 0%  -1.55% (p=0.002 n=6)
RLS/Sample-15000/config_names/Without_RLS-4         14.26m ± 2%    14.33m ± 2%       ~ (p=0.818 n=6)
RLS/Sample-15000/config_names/With_RLS-4            139.0m ± 0%    139.9m ± 1%  +0.62% (p=0.004 n=6)
RLS/Sample-15000/config_summary/Without_RLS-4       98.91m ± 1%   100.33m ± 2%       ~ (p=0.240 n=6)
RLS/Sample-15000/config_summary/With_RLS-4          716.5m ± 1%    721.3m ± 1%       ~ (p=0.065 n=6)
RLS/Sample-15000/configs/Without_RLS-4              8.269m ± 3%    8.410m ± 4%       ~ (p=0.394 n=6)
RLS/Sample-15000/configs/With_RLS-4                 135.7m ± 1%    137.7m ± 0%  +1.45% (p=0.002 n=6)
RLS/Sample-15000/analysis_types/Without_RLS-4       3.895m ± 1%    3.900m ± 2%       ~ (p=0.394 n=6)
RLS/Sample-15000/analysis_types/With_RLS-4          3.931m ± 3%    3.904m ± 3%  -0.68% (p=0.041 n=6)
RLS/Sample-15000/analyzer_types/Without_RLS-4       3.721m ± 2%    3.708m ± 2%       ~ (p=0.132 n=6)
RLS/Sample-15000/analyzer_types/With_RLS-4          3.761m ± 3%    3.756m ± 0%       ~ (p=0.589 n=6)
RLS/Sample-15000/change_types/Without_RLS-4         5.310m ± 1%    5.385m ± 2%  +1.42% (p=0.009 n=6)
RLS/Sample-15000/change_types/With_RLS-4            5.544m ± 2%    5.275m ± 2%  -4.86% (p=0.002 n=6)
RLS/Sample-15000/config_classes/Without_RLS-4       4.127m ± 1%    4.127m ± 2%       ~ (p=0.937 n=6)
RLS/Sample-15000/config_classes/With_RLS-4          135.1m ± 0%    136.5m ± 1%  +1.06% (p=0.002 n=6)
RLS/Sample-15000/config_types/Without_RLS-4         4.801m ± 1%    4.790m ± 4%       ~ (p=0.937 n=6)
RLS/Sample-15000/config_types/With_RLS-4            135.9m ± 3%    136.6m ± 1%       ~ (p=0.240 n=6)
geomean                                             21.13m         21.11m       -0.08%

@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 5, 2026

Benchstat (Other)

Base: 617b11d4451d2f93ce8aa22f89b34eebcdc8686d
Head: 0c52d9349ec8065be23df000780b497275c53c90

✅ No significant performance changes detected

Full benchstat output
goos: linux
goarch: amd64
pkg: github.com/flanksource/duty/bench
cpu: AMD EPYC 7763 64-Core Processor                
                                                       │ bench-base.txt │           bench-head.txt           │
                                                       │     sec/op     │    sec/op     vs base              │
InsertionForRowsWithAliases/external_users.aliases-4       585.4µ ±  1%   580.7µ ±  4%       ~ (p=0.394 n=6)
InsertionForRowsWithAliases/config_items.external_id-4     1.094m ± 11%   1.100m ± 10%       ~ (p=0.699 n=6)
InsertionOfConfigsWithProperties-4                         3.688m ±  2%   3.669m ±  1%       ~ (p=0.065 n=6)
UpdateOfConfigsWithProperties-4                            7.432m ±  1%   7.482m ±  1%       ~ (p=0.180 n=6)
ResourceSelectorConfigs/name-4                             220.9µ ±  2%   221.2µ ±  3%       ~ (p=0.818 n=6)
ResourceSelectorConfigs/name_and_type-4                    240.2µ ±  4%   238.0µ ±  5%       ~ (p=0.310 n=6)
ResourceSelectorConfigs/tags-4                             29.76m ±  3%   28.93m ±  4%       ~ (p=0.093 n=6)
ResourceSelectorQueryBuild/name-4                          42.68µ ±  1%   42.44µ ±  3%       ~ (p=0.240 n=6)
ResourceSelectorQueryBuild/name_and_type-4                 63.92µ ±  3%   63.19µ ±  1%       ~ (p=0.132 n=6)
ResourceSelectorQueryBuild/tags-4                          16.77µ ±  2%   16.77µ ±  1%       ~ (p=0.937 n=6)
geomean                                                    513.2µ         510.5µ        -0.54%

@adityathebe adityathebe force-pushed the feat/config-properties-normalized branch from 1683ff4 to ccf81b6 Compare May 5, 2026 15:58
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🧹 Nitpick comments (1)
views/006_config_views.sql (1)

156-199: config_properties_json is a regular view, not materialized — consider the full-scan cost for configs.

configs selects all rows from config_items_with_properties, which in turn groups and aggregates the entire config_properties table via config_properties_json. For a single config-detail lookup this is fine (the planner can push the config_id predicate), but for list queries (e.g., SELECT * FROM configs) the aggregation runs across all config_properties rows on every request.

If config_properties grows large (high-volume scrapers writing many properties per item), consider materializing config_properties_json with a refresh trigger/job on INSERT/UPDATE/DELETE on config_properties.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@views/006_config_views.sql` around lines 156 - 199, The view
config_items_with_properties joins to config_properties_json (a regular view)
which causes full aggregation of config_properties on list queries (e.g.,
configs SELECT *), so replace config_properties_json with a MATERIALIZED VIEW
and add a refresh strategy: create a materialized view for
config_properties_json, populate it initially, and implement a refresh mechanism
(either triggers or a background refresh job) that refreshes the matview on
INSERT/UPDATE/DELETE to config_properties; ensure refreshes are transactional or
use CONCURRENTLY if needed and update any consumers that assume the view
name/columns (config_items_with_properties, configs) to point to the matview.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@models/config.go`:
- Around line 203-232: The NewConfigProperty function currently only uses the
first element of types.Property.Links and silently ignores additional links;
update the code by adding a clear doc comment above NewConfigProperty (and
optionally on the ConfigProperty type) that states the function and table schema
only store a single link (LinkURL/LinkLabel/LinkIcon) and any extra links in
types.Property will be dropped, referencing NewConfigProperty, ConfigProperty,
and types.Property so callers are aware; if you prefer API behavior change
instead, outline in the comment that a follow-up task will be required to
support multiple links and where to modify (NewConfigProperty and the DB
schema).

In `@views/006_config_views.sql`:
- Around line 138-148: The JSON for the "links" array omits the inlined Text
fields from types.Link; update the jsonb_build_object inside the CASE that
creates "links" (the block referencing link_url, link_label, link_icon) to also
include the inlined fields 'type', 'tooltip', and 'text' (e.g., map to columns
such as link_type, link_tooltip, link_text or the actual column names used) so
the jsonb_build_object produces {'type', 'url', 'label', 'icon', 'tooltip',
'text'} and then jsonb_strip_nulls/jsonb_build_array as before to avoid data
loss when serializing/deserializing types.Link.

In `@views/9998_rls_enable.sql`:
- Around line 181-194: The new RLS policy config_properties_auth won't be
applied when accessed through views that run as their owner, so add ALTER VIEW
... SECURITY_INVOKER for the views that currently default to security_definer:
set security_invoker = true on config_items_with_properties and
config_properties_json (place these ALTER VIEW statements next to the existing
security-invoker block that already sets configs and config_detail) so those
views execute as the calling PostgREST role and allow the config_properties_auth
policy to be enforced.

---

Nitpick comments:
In `@views/006_config_views.sql`:
- Around line 156-199: The view config_items_with_properties joins to
config_properties_json (a regular view) which causes full aggregation of
config_properties on list queries (e.g., configs SELECT *), so replace
config_properties_json with a MATERIALIZED VIEW and add a refresh strategy:
create a materialized view for config_properties_json, populate it initially,
and implement a refresh mechanism (either triggers or a background refresh job)
that refreshes the matview on INSERT/UPDATE/DELETE to config_properties; ensure
refreshes are transactional or use CONCURRENTLY if needed and update any
consumers that assume the view name/columns (config_items_with_properties,
configs) to point to the matview.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 2f0e55b2-c034-4627-92b6-9bb0edf21f91

📥 Commits

Reviewing files that changed from the base of the PR and between 56f947a and 1683ff4.

📒 Files selected for processing (7)
  • models/config.go
  • rbac/objects.go
  • schema/config.hcl
  • views/006_config_views.sql
  • views/038_config_access.sql
  • views/9998_rls_enable.sql
  • views/9999_rls_disable.sql

Comment thread models/config.go
Comment thread views/006_config_views.sql
Comment thread views/9998_rls_enable.sql
The config access migration recreates config_access_summary, but some databases can still have the old external_group_summary view depending on it.

Drop the stale dependent view before dropping config_access_summary so the migration can proceed without using CASCADE.
Add a normalized config_properties table for properties created by scrapers or users, with foreign keys, creator validation, and uniqueness per creator/name.

Expose typed properties through JSON compatibility views and merge them into configs and config_detail while keeping existing scraper-written config_items.properties intact.
Set security_invoker on the new config property compatibility views so configs and config_detail continue to enforce config_items RLS through nested view reads.
@adityathebe adityathebe force-pushed the feat/config-properties-normalized branch from 2f51bc8 to 0c52d93 Compare May 8, 2026 13:09
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.

1 participant