configmanbearpig 2.0.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- configmanbearpig-2.0.0/.agents/skills/grill-me/SKILL.md +20 -0
- configmanbearpig-2.0.0/.agents/skills/openhound/SKILL.md +46 -0
- configmanbearpig-2.0.0/.agents/skills/openhound/references/add-asset.md +177 -0
- configmanbearpig-2.0.0/.agents/skills/openhound/references/graph-schema.md +114 -0
- configmanbearpig-2.0.0/.agents/skills/openhound/references/plan-collector.md +120 -0
- configmanbearpig-2.0.0/.agents/skills/openhound/references/preproc-lookup.md +154 -0
- configmanbearpig-2.0.0/.agents/skills/openhound/references/register-extension.md +132 -0
- configmanbearpig-2.0.0/.agents/skills/openhound/references/source-collection.md +119 -0
- configmanbearpig-2.0.0/.agents/skills/openhound/references/validate-extension.md +70 -0
- configmanbearpig-2.0.0/.agents/standards/openhound.md +62 -0
- configmanbearpig-2.0.0/.agents/standards/workflow.md +39 -0
- configmanbearpig-2.0.0/.gitattributes +15 -0
- configmanbearpig-2.0.0/.github/workflows/ci.yml +42 -0
- configmanbearpig-2.0.0/.github/workflows/release.yml +101 -0
- configmanbearpig-2.0.0/.gitignore +241 -0
- configmanbearpig-2.0.0/.pre-commit-config.yaml +13 -0
- configmanbearpig-2.0.0/.tickets/Ope-0t3h.md +24 -0
- configmanbearpig-2.0.0/.tickets/Ope-15m7.md +110 -0
- configmanbearpig-2.0.0/.tickets/Ope-4tdt.md +44 -0
- configmanbearpig-2.0.0/.tickets/Ope-6cei.md +24 -0
- configmanbearpig-2.0.0/.tickets/Ope-8wi2.md +37 -0
- configmanbearpig-2.0.0/.tickets/Ope-bmyk.md +29 -0
- configmanbearpig-2.0.0/.tickets/Ope-emhc.md +29 -0
- configmanbearpig-2.0.0/.tickets/Ope-ew5k.md +29 -0
- configmanbearpig-2.0.0/.tickets/Ope-exvi.md +23 -0
- configmanbearpig-2.0.0/.tickets/Ope-f3di.md +59 -0
- configmanbearpig-2.0.0/.tickets/Ope-gqwo.md +23 -0
- configmanbearpig-2.0.0/.tickets/Ope-l6fu.md +24 -0
- configmanbearpig-2.0.0/.tickets/Ope-liu7.md +29 -0
- configmanbearpig-2.0.0/.tickets/Ope-o008.md +29 -0
- configmanbearpig-2.0.0/.tickets/Ope-o6bh.md +24 -0
- configmanbearpig-2.0.0/.tickets/Ope-padv.md +23 -0
- configmanbearpig-2.0.0/.tickets/Ope-pofz.md +18 -0
- configmanbearpig-2.0.0/.tickets/Ope-rhzx.md +33 -0
- configmanbearpig-2.0.0/.tickets/Ope-scp1.md +39 -0
- configmanbearpig-2.0.0/.tickets/Ope-t7kv.md +33 -0
- configmanbearpig-2.0.0/.tickets/Ope-txs0.md +24 -0
- configmanbearpig-2.0.0/.tickets/Ope-vpdw.md +18 -0
- configmanbearpig-2.0.0/.tickets/Ope-zaja.md +24 -0
- configmanbearpig-2.0.0/.tickets/_TICKETS-BY-STATUS.md +170 -0
- configmanbearpig-2.0.0/.tickets/con-0170.md +24 -0
- configmanbearpig-2.0.0/.tickets/con-0289.md +30 -0
- configmanbearpig-2.0.0/.tickets/con-0394.md +44 -0
- configmanbearpig-2.0.0/.tickets/con-2249.md +24 -0
- configmanbearpig-2.0.0/.tickets/con-2ca2.md +43 -0
- configmanbearpig-2.0.0/.tickets/con-3354.md +63 -0
- configmanbearpig-2.0.0/.tickets/con-3be4.md +28 -0
- configmanbearpig-2.0.0/.tickets/con-401c.md +32 -0
- configmanbearpig-2.0.0/.tickets/con-53eb.md +30 -0
- configmanbearpig-2.0.0/.tickets/con-5e71.md +27 -0
- configmanbearpig-2.0.0/.tickets/con-6198.md +30 -0
- configmanbearpig-2.0.0/.tickets/con-6677.md +28 -0
- configmanbearpig-2.0.0/.tickets/con-68c2.md +33 -0
- configmanbearpig-2.0.0/.tickets/con-727a.md +40 -0
- configmanbearpig-2.0.0/.tickets/con-7296.md +19 -0
- configmanbearpig-2.0.0/.tickets/con-7741.md +27 -0
- configmanbearpig-2.0.0/.tickets/con-7842.md +22 -0
- configmanbearpig-2.0.0/.tickets/con-894a.md +22 -0
- configmanbearpig-2.0.0/.tickets/con-8a28.md +45 -0
- configmanbearpig-2.0.0/.tickets/con-8a33.md +25 -0
- configmanbearpig-2.0.0/.tickets/con-907c.md +54 -0
- configmanbearpig-2.0.0/.tickets/con-a4ec.md +42 -0
- configmanbearpig-2.0.0/.tickets/con-ab59.md +63 -0
- configmanbearpig-2.0.0/.tickets/con-acdd.md +27 -0
- configmanbearpig-2.0.0/.tickets/con-be15.md +66 -0
- configmanbearpig-2.0.0/.tickets/con-be32.md +23 -0
- configmanbearpig-2.0.0/.tickets/con-c509.md +46 -0
- configmanbearpig-2.0.0/.tickets/con-c522.md +28 -0
- configmanbearpig-2.0.0/.tickets/con-c542.md +28 -0
- configmanbearpig-2.0.0/.tickets/con-d061.md +26 -0
- configmanbearpig-2.0.0/.tickets/con-d857.md +11 -0
- configmanbearpig-2.0.0/.tickets/con-e455.md +32 -0
- configmanbearpig-2.0.0/.tickets/con-edee.md +27 -0
- configmanbearpig-2.0.0/.tickets/ope-00ca.md +20 -0
- configmanbearpig-2.0.0/.tickets/ope-00df.md +13 -0
- configmanbearpig-2.0.0/.tickets/ope-0112.md +17 -0
- configmanbearpig-2.0.0/.tickets/ope-0495.md +31 -0
- configmanbearpig-2.0.0/.tickets/ope-065f.md +16 -0
- configmanbearpig-2.0.0/.tickets/ope-0947.md +62 -0
- configmanbearpig-2.0.0/.tickets/ope-0f66.md +14 -0
- configmanbearpig-2.0.0/.tickets/ope-1172.md +11 -0
- configmanbearpig-2.0.0/.tickets/ope-1201.md +20 -0
- configmanbearpig-2.0.0/.tickets/ope-140f.md +13 -0
- configmanbearpig-2.0.0/.tickets/ope-16f5.md +24 -0
- configmanbearpig-2.0.0/.tickets/ope-194a.md +13 -0
- configmanbearpig-2.0.0/.tickets/ope-1950.md +21 -0
- configmanbearpig-2.0.0/.tickets/ope-1d06.md +18 -0
- configmanbearpig-2.0.0/.tickets/ope-1f0f.md +68 -0
- configmanbearpig-2.0.0/.tickets/ope-1f49.md +76 -0
- configmanbearpig-2.0.0/.tickets/ope-215a.md +17 -0
- configmanbearpig-2.0.0/.tickets/ope-2419.md +18 -0
- configmanbearpig-2.0.0/.tickets/ope-255b.md +15 -0
- configmanbearpig-2.0.0/.tickets/ope-272e.md +21 -0
- configmanbearpig-2.0.0/.tickets/ope-272f.md +26 -0
- configmanbearpig-2.0.0/.tickets/ope-2732.md +24 -0
- configmanbearpig-2.0.0/.tickets/ope-2f15.md +20 -0
- configmanbearpig-2.0.0/.tickets/ope-2ff3.md +15 -0
- configmanbearpig-2.0.0/.tickets/ope-334f.md +21 -0
- configmanbearpig-2.0.0/.tickets/ope-38ad.md +21 -0
- configmanbearpig-2.0.0/.tickets/ope-3d28.md +21 -0
- configmanbearpig-2.0.0/.tickets/ope-3dbc.md +20 -0
- configmanbearpig-2.0.0/.tickets/ope-3de2.md +13 -0
- configmanbearpig-2.0.0/.tickets/ope-3f2a.md +21 -0
- configmanbearpig-2.0.0/.tickets/ope-4483.md +33 -0
- configmanbearpig-2.0.0/.tickets/ope-46ef.md +14 -0
- configmanbearpig-2.0.0/.tickets/ope-4787.md +11 -0
- configmanbearpig-2.0.0/.tickets/ope-4ba1.md +20 -0
- configmanbearpig-2.0.0/.tickets/ope-4c6f.md +18 -0
- configmanbearpig-2.0.0/.tickets/ope-50cc.md +18 -0
- configmanbearpig-2.0.0/.tickets/ope-5186.md +20 -0
- configmanbearpig-2.0.0/.tickets/ope-5271.md +25 -0
- configmanbearpig-2.0.0/.tickets/ope-54be.md +27 -0
- configmanbearpig-2.0.0/.tickets/ope-57cf.md +13 -0
- configmanbearpig-2.0.0/.tickets/ope-60fe.md +73 -0
- configmanbearpig-2.0.0/.tickets/ope-6569.md +20 -0
- configmanbearpig-2.0.0/.tickets/ope-6716.md +24 -0
- configmanbearpig-2.0.0/.tickets/ope-676f.md +17 -0
- configmanbearpig-2.0.0/.tickets/ope-6aa7.md +15 -0
- configmanbearpig-2.0.0/.tickets/ope-6b93.md +20 -0
- configmanbearpig-2.0.0/.tickets/ope-7313.md +21 -0
- configmanbearpig-2.0.0/.tickets/ope-76f1.md +23 -0
- configmanbearpig-2.0.0/.tickets/ope-7da1.md +20 -0
- configmanbearpig-2.0.0/.tickets/ope-7e54.md +70 -0
- configmanbearpig-2.0.0/.tickets/ope-7f61.md +14 -0
- configmanbearpig-2.0.0/.tickets/ope-86f8.md +13 -0
- configmanbearpig-2.0.0/.tickets/ope-8b99.md +23 -0
- configmanbearpig-2.0.0/.tickets/ope-8c44.md +24 -0
- configmanbearpig-2.0.0/.tickets/ope-90fc.md +15 -0
- configmanbearpig-2.0.0/.tickets/ope-9271.md +29 -0
- configmanbearpig-2.0.0/.tickets/ope-961c.md +18 -0
- configmanbearpig-2.0.0/.tickets/ope-9989.md +28 -0
- configmanbearpig-2.0.0/.tickets/ope-9d62.md +11 -0
- configmanbearpig-2.0.0/.tickets/ope-a214.md +24 -0
- configmanbearpig-2.0.0/.tickets/ope-a88e.md +21 -0
- configmanbearpig-2.0.0/.tickets/ope-aa39.md +60 -0
- configmanbearpig-2.0.0/.tickets/ope-ad1c.md +12 -0
- configmanbearpig-2.0.0/.tickets/ope-afc8.md +25 -0
- configmanbearpig-2.0.0/.tickets/ope-b1e8.md +20 -0
- configmanbearpig-2.0.0/.tickets/ope-b287.md +17 -0
- configmanbearpig-2.0.0/.tickets/ope-b7b2.md +24 -0
- configmanbearpig-2.0.0/.tickets/ope-b916.md +36 -0
- configmanbearpig-2.0.0/.tickets/ope-c0c0.md +20 -0
- configmanbearpig-2.0.0/.tickets/ope-c141.md +20 -0
- configmanbearpig-2.0.0/.tickets/ope-c660.md +17 -0
- configmanbearpig-2.0.0/.tickets/ope-c8cc.md +26 -0
- configmanbearpig-2.0.0/.tickets/ope-c8dd.md +14 -0
- configmanbearpig-2.0.0/.tickets/ope-cc0f.md +24 -0
- configmanbearpig-2.0.0/.tickets/ope-d57d.md +28 -0
- configmanbearpig-2.0.0/.tickets/ope-d820.md +15 -0
- configmanbearpig-2.0.0/.tickets/ope-da2a.md +19 -0
- configmanbearpig-2.0.0/.tickets/ope-df0e.md +13 -0
- configmanbearpig-2.0.0/.tickets/ope-e10b.md +14 -0
- configmanbearpig-2.0.0/.tickets/ope-e191.md +38 -0
- configmanbearpig-2.0.0/.tickets/ope-e512.md +17 -0
- configmanbearpig-2.0.0/.tickets/ope-e739.md +28 -0
- configmanbearpig-2.0.0/.tickets/ope-ec50.md +13 -0
- configmanbearpig-2.0.0/.tickets/ope-f173.md +17 -0
- configmanbearpig-2.0.0/.tickets/ope-f1ce.md +18 -0
- configmanbearpig-2.0.0/.tickets/ope-f27c.md +19 -0
- configmanbearpig-2.0.0/.tickets/ope-f651.md +18 -0
- configmanbearpig-2.0.0/.tickets/ope-fb99.md +20 -0
- configmanbearpig-2.0.0/.tickets/ope-fbb0.md +20 -0
- configmanbearpig-2.0.0/.tickets/ope-feb0.md +24 -0
- configmanbearpig-2.0.0/.tickets/ope-ff28.md +14 -0
- configmanbearpig-2.0.0/AGENTS.md +210 -0
- configmanbearpig-2.0.0/ARCHITECTURE.md +2090 -0
- configmanbearpig-2.0.0/CLAUDE.md +69 -0
- configmanbearpig-2.0.0/LICENSE +201 -0
- configmanbearpig-2.0.0/PKG-INFO +2499 -0
- configmanbearpig-2.0.0/README.md +2471 -0
- configmanbearpig-2.0.0/cypher_queries/SCCM Admin Logon Sessions.json +1 -0
- configmanbearpig-2.0.0/cypher_queries/SCCM Admin Users.json +1 -0
- configmanbearpig-2.0.0/cypher_queries/SCCM Admins Who Can Escalate Other Admins.json +1 -0
- configmanbearpig-2.0.0/cypher_queries/SCCM CRED-3.json +1 -0
- configmanbearpig-2.0.0/cypher_queries/SCCM CRED-5.json +1 -0
- configmanbearpig-2.0.0/cypher_queries/SCCM Client Device Users.json +1 -0
- configmanbearpig-2.0.0/cypher_queries/SCCM ELEVATE-1.json +1 -0
- configmanbearpig-2.0.0/cypher_queries/SCCM Hierarchy TAKEOVER-1.json +1 -0
- configmanbearpig-2.0.0/cypher_queries/SCCM Hierarchy TAKEOVER-2.json +1 -0
- configmanbearpig-2.0.0/cypher_queries/SCCM Hierarchy TAKEOVER-3.json +1 -0
- configmanbearpig-2.0.0/cypher_queries/SCCM Hierarchy TAKEOVER-4.json +1 -0
- configmanbearpig-2.0.0/cypher_queries/SCCM Hierarchy TAKEOVER-5.json +1 -0
- configmanbearpig-2.0.0/cypher_queries/SCCM Hierarchy TAKEOVER-6.json +1 -0
- configmanbearpig-2.0.0/cypher_queries/SCCM Hierarchy TAKEOVER-7.json +1 -0
- configmanbearpig-2.0.0/cypher_queries/SCCM Hierarchy TAKEOVER-8.json +1 -0
- configmanbearpig-2.0.0/cypher_queries/SCCM Hierarchy TAKEOVER-9.json +1 -0
- configmanbearpig-2.0.0/cypher_queries/SCCM Hierarchy TAKEOVERs.json +1 -0
- configmanbearpig-2.0.0/cypher_queries/SCCM Infrastructure Logons.json +1 -0
- configmanbearpig-2.0.0/cypher_queries/SCCM Infrastructure.json +1 -0
- configmanbearpig-2.0.0/cypher_queries/SCCM Principals with Full Control of System Management Container (Possible Site Servers).json +1 -0
- configmanbearpig-2.0.0/cypher_queries/SCCM Shortest TAKEOVER Path.json +1 -0
- configmanbearpig-2.0.0/cypher_queries/SCCM Site Database Service Account to Client Device.json +1 -0
- configmanbearpig-2.0.0/cypher_queries/SCCM Site Server Has Local Admin on Site System Roles.json +1 -0
- configmanbearpig-2.0.0/cypher_queries/SCCM Sites.json +1 -0
- configmanbearpig-2.0.0/dev/_ab_cmbp.py +47 -0
- configmanbearpig-2.0.0/dev/ab_matrix.py +187 -0
- configmanbearpig-2.0.0/dev/debug_epa_matrix.py +613 -0
- configmanbearpig-2.0.0/dev/debug_per_host.py +192 -0
- configmanbearpig-2.0.0/dev/debug_smb_auth.py +178 -0
- configmanbearpig-2.0.0/dev/debug_wmi_auth.py +166 -0
- configmanbearpig-2.0.0/dev/regen_ticket_index.py +155 -0
- configmanbearpig-2.0.0/dev/spike_smb_sso.py +149 -0
- configmanbearpig-2.0.0/dev/spike_socks_proxy.md +179 -0
- configmanbearpig-2.0.0/dev/tour_driver_stage0.py +24 -0
- configmanbearpig-2.0.0/dev/tour_driver_stage1.py +106 -0
- configmanbearpig-2.0.0/dev/tour_driver_stage2.py +152 -0
- configmanbearpig-2.0.0/dev/tour_driver_stage3.py +401 -0
- configmanbearpig-2.0.0/docs/PUBLISHING.md +771 -0
- configmanbearpig-2.0.0/docs/per-host-collection-framework-tour.md +314 -0
- configmanbearpig-2.0.0/docs/proposals/2026-06-16-computer-node-multi-driver-merge.md +322 -0
- configmanbearpig-2.0.0/docs/proposals/2026-06-16-convert-read-from-duckdb.md +314 -0
- configmanbearpig-2.0.0/docs/superpowers/plans/2026-05-26-ldap-management-points-raw.md +822 -0
- configmanbearpig-2.0.0/docs/superpowers/plans/2026-05-29-dns-resolver-flag.md +535 -0
- configmanbearpig-2.0.0/docs/superpowers/plans/2026-06-03-per-host-collection-framework.md +377 -0
- configmanbearpig-2.0.0/docs/superpowers/plans/2026-06-04-impacket-sspi-smb-sso.md +850 -0
- configmanbearpig-2.0.0/docs/superpowers/plans/2026-06-09-sccm-adminservice-collector.md +1025 -0
- configmanbearpig-2.0.0/docs/superpowers/plans/2026-06-09-sccm-http-client.md +1269 -0
- configmanbearpig-2.0.0/docs/superpowers/plans/2026-06-11-sccm-wmi-fallback-collector.md +518 -0
- configmanbearpig-2.0.0/docs/superpowers/plans/2026-06-12-merge-privileged-collectors.md +805 -0
- configmanbearpig-2.0.0/docs/superpowers/plans/2026-06-15-sccm-http-collector.md +271 -0
- configmanbearpig-2.0.0/docs/superpowers/plans/2026-06-16-sccm-preproc-convert-stage0-validation.md +118 -0
- configmanbearpig-2.0.0/docs/superpowers/plans/2026-06-16-sccm-preproc-convert-stage0.md +636 -0
- configmanbearpig-2.0.0/docs/superpowers/plans/2026-06-17-sccm-preproc-convert-stage1-validation.md +215 -0
- configmanbearpig-2.0.0/docs/superpowers/plans/2026-06-17-sccm-preproc-convert-stage1.md +826 -0
- configmanbearpig-2.0.0/docs/superpowers/plans/2026-06-23-sccm-preproc-convert-stage2-validation.md +85 -0
- configmanbearpig-2.0.0/docs/superpowers/plans/2026-06-23-sccm-preproc-convert-stage2.md +965 -0
- configmanbearpig-2.0.0/docs/superpowers/plans/2026-06-24-sccm-preproc-convert-stage3-validation.md +368 -0
- configmanbearpig-2.0.0/docs/superpowers/plans/2026-06-24-sccm-preproc-convert-stage3.md +935 -0
- configmanbearpig-2.0.0/docs/superpowers/plans/2026-06-24-stage3-property-matrix.md +249 -0
- configmanbearpig-2.0.0/docs/superpowers/plans/2026-06-26-sccm-cmbp-property-casing.md +242 -0
- configmanbearpig-2.0.0/docs/superpowers/plans/2026-06-29-collect-summary-per-run-metric.md +503 -0
- configmanbearpig-2.0.0/docs/superpowers/plans/2026-06-29-sccm-preproc-convert-stage4-validation.md +323 -0
- configmanbearpig-2.0.0/docs/superpowers/plans/2026-06-29-sccm-preproc-convert-stage4.md +930 -0
- configmanbearpig-2.0.0/docs/superpowers/plans/2026-06-29-sccm-preproc-convert-stage5-validation.md +608 -0
- configmanbearpig-2.0.0/docs/superpowers/plans/2026-06-29-sccm-preproc-convert-stage5.md +1964 -0
- configmanbearpig-2.0.0/docs/superpowers/plans/2026-06-29-split-ad-nodes-edges-output.md +786 -0
- configmanbearpig-2.0.0/docs/superpowers/plans/2026-06-30-sccm-preproc-convert-stage6-validation.md +640 -0
- configmanbearpig-2.0.0/docs/superpowers/plans/2026-06-30-sccm-preproc-convert-stage6.md +1273 -0
- configmanbearpig-2.0.0/docs/superpowers/plans/2026-07-01-sccm-preproc-convert-stage7-validation.md +195 -0
- configmanbearpig-2.0.0/docs/superpowers/plans/2026-07-01-sccm-preproc-convert-stage7.md +567 -0
- configmanbearpig-2.0.0/docs/superpowers/plans/2026-07-15-edge-entity-panel-help.md +629 -0
- configmanbearpig-2.0.0/docs/superpowers/plans/2026-07-16-openhound-run-all-shared-orchestrator.md +748 -0
- configmanbearpig-2.0.0/docs/superpowers/plans/2026-07-17-sccm-version-cve-fingerprint.md +693 -0
- configmanbearpig-2.0.0/docs/superpowers/plans/2026-07-17-socks5-proxy-all-collection-traffic.md +1137 -0
- configmanbearpig-2.0.0/docs/superpowers/plans/2026-07-21-ope-b7b2-ldap-pth-ptt-and-mssql-ticket-warning.md +436 -0
- configmanbearpig-2.0.0/docs/superpowers/plans/2026-07-21-tier1-tier2-smc-abuse-and-cleanup.md +227 -0
- configmanbearpig-2.0.0/docs/superpowers/plans/2026-07-22-dc-only-flag.md +416 -0
- configmanbearpig-2.0.0/docs/superpowers/plans/2026-07-22-sccm-integration-test-kit.md +1576 -0
- configmanbearpig-2.0.0/docs/superpowers/plans/2026-07-23-cmbp-parity-node-edge-properties.md +413 -0
- configmanbearpig-2.0.0/docs/superpowers/plans/2026-07-23-low-priv-assumed-edges.md +1753 -0
- configmanbearpig-2.0.0/docs/superpowers/plans/2026-07-24-sccm-repo-cleanup.md +1047 -0
- configmanbearpig-2.0.0/docs/superpowers/plans/2026-07-29-multi-agent-concurrency.md +345 -0
- configmanbearpig-2.0.0/docs/superpowers/plans/2026-07-30-docs-update-readme-architecture.md +415 -0
- configmanbearpig-2.0.0/docs/superpowers/plans/2026-07-30-mssql-split-output.md +906 -0
- configmanbearpig-2.0.0/docs/superpowers/plans/2026-07-31-compare-and-privilege-gating.md +1729 -0
- configmanbearpig-2.0.0/docs/superpowers/specs/2026-05-26-ldap-management-points-raw-design.md +127 -0
- configmanbearpig-2.0.0/docs/superpowers/specs/2026-05-29-dns-resolver-flag-design.md +125 -0
- configmanbearpig-2.0.0/docs/superpowers/specs/2026-06-04-impacket-sspi-smb-sso-design.md +212 -0
- configmanbearpig-2.0.0/docs/superpowers/specs/2026-06-09-sccm-adminservice-collector-design.md +175 -0
- configmanbearpig-2.0.0/docs/superpowers/specs/2026-06-09-sccm-http-client-design.md +237 -0
- configmanbearpig-2.0.0/docs/superpowers/specs/2026-06-12-merge-privileged-collectors-design.md +186 -0
- configmanbearpig-2.0.0/docs/superpowers/specs/2026-06-15-smb-collector-design.md +207 -0
- configmanbearpig-2.0.0/docs/superpowers/specs/2026-06-16-sccm-preproc-convert-design.md +494 -0
- configmanbearpig-2.0.0/docs/superpowers/specs/2026-07-02-sccm-shared-lib-migration-design.md +263 -0
- configmanbearpig-2.0.0/docs/superpowers/specs/2026-07-15-edge-entity-panel-help-design.md +247 -0
- configmanbearpig-2.0.0/docs/superpowers/specs/2026-07-17-sccm-version-cve-fingerprint-design.md +187 -0
- configmanbearpig-2.0.0/docs/superpowers/specs/2026-07-22-sccm-integration-test-kit-design.md +143 -0
- configmanbearpig-2.0.0/docs/superpowers/specs/2026-07-23-cmbp-parity-node-edge-properties-design.md +143 -0
- configmanbearpig-2.0.0/docs/superpowers/specs/2026-07-23-low-priv-assumed-edges-design.md +411 -0
- configmanbearpig-2.0.0/docs/superpowers/specs/2026-07-27-publishing-and-repo-split-design.md +360 -0
- configmanbearpig-2.0.0/docs/superpowers/specs/2026-07-29-multi-agent-concurrency-design.md +415 -0
- configmanbearpig-2.0.0/docs/superpowers/specs/2026-07-31-compare-and-privilege-gating-design.md +259 -0
- configmanbearpig-2.0.0/powershell_deprecated/ConfigManBearPig.ps1 +10441 -0
- configmanbearpig-2.0.0/powershell_deprecated/Invoke-ConfigManBearPigUnitTests.ps1 +2019 -0
- configmanbearpig-2.0.0/powershell_deprecated/README.md +466 -0
- configmanbearpig-2.0.0/powershell_deprecated/RELEASE_NOTES.md +13 -0
- configmanbearpig-2.0.0/powershell_deprecated/bloodhound-sccm-20260801-133910.zip +0 -0
- configmanbearpig-2.0.0/powershell_deprecated/sample_data/upload_1_20260101144303_BloodHound_for_TAKEOVERs-3-and-8.zip +0 -0
- configmanbearpig-2.0.0/powershell_deprecated/sample_data/upload_1_bloodhound-sccm-noprivs-allpossibleedges-nobadopsec.zip +0 -0
- configmanbearpig-2.0.0/powershell_deprecated/sample_data/upload_2_bloodhound-sccm-noprivs-allpossibleedges-enablebadopsec.zip +0 -0
- configmanbearpig-2.0.0/powershell_deprecated/sample_data/upload_3_bloodhound-sccm-privileged.zip +0 -0
- configmanbearpig-2.0.0/powershell_deprecated/sample_data/upload_3_mssql-bloodhound-privileged.zip +0 -0
- configmanbearpig-2.0.0/powershell_deprecated/seed_data.json +50 -0
- configmanbearpig-2.0.0/pyproject.toml +224 -0
- configmanbearpig-2.0.0/sample_data/README.md +70 -0
- configmanbearpig-2.0.0/sample_data/configmanbearpig_collect_full_privileged_all-possible-edges_20260801_225955.log +3558 -0
- configmanbearpig-2.0.0/sample_data/configmanbearpig_collect_full_privileged_disable-possible-edges_20260801_230109.log +3560 -0
- configmanbearpig-2.0.0/sample_data/configmanbearpig_collect_full_unprivileged_all-possible-edges_20260801_230258.log +2222 -0
- configmanbearpig-2.0.0/sample_data/configmanbearpig_collect_full_unprivileged_disable-possible-edges_20260801_230714.log +2220 -0
- configmanbearpig-2.0.0/sample_data/configmanbearpig_collection_privileged_all-possible-edges_20260801_225955.zip +0 -0
- configmanbearpig-2.0.0/sample_data/configmanbearpig_collection_privileged_disable-possible-edges_20260801_230109.zip +0 -0
- configmanbearpig-2.0.0/sample_data/configmanbearpig_collection_unprivileged_all-possible-edges_20260801_230258.zip +0 -0
- configmanbearpig-2.0.0/sample_data/configmanbearpig_collection_unprivileged_disable-possible-edges_20260801_230714.zip +0 -0
- configmanbearpig-2.0.0/src/openhound_sccm/__init__.py +0 -0
- configmanbearpig-2.0.0/src/openhound_sccm/clients/__init__.py +0 -0
- configmanbearpig-2.0.0/src/openhound_sccm/clients/ad.py +296 -0
- configmanbearpig-2.0.0/src/openhound_sccm/clients/http.py +283 -0
- configmanbearpig-2.0.0/src/openhound_sccm/clients/http_auth.py +206 -0
- configmanbearpig-2.0.0/src/openhound_sccm/clients/mssql_epa.py +129 -0
- configmanbearpig-2.0.0/src/openhound_sccm/clients/smb.py +175 -0
- configmanbearpig-2.0.0/src/openhound_sccm/clients/smb_sso.py +289 -0
- configmanbearpig-2.0.0/src/openhound_sccm/clients/wmi.py +214 -0
- configmanbearpig-2.0.0/src/openhound_sccm/collectors/__init__.py +0 -0
- configmanbearpig-2.0.0/src/openhound_sccm/collectors/dns.py +278 -0
- configmanbearpig-2.0.0/src/openhound_sccm/collectors/http.py +559 -0
- configmanbearpig-2.0.0/src/openhound_sccm/collectors/ldap.py +879 -0
- configmanbearpig-2.0.0/src/openhound_sccm/collectors/local.py +349 -0
- configmanbearpig-2.0.0/src/openhound_sccm/collectors/mssql.py +179 -0
- configmanbearpig-2.0.0/src/openhound_sccm/collectors/privileged.py +423 -0
- configmanbearpig-2.0.0/src/openhound_sccm/collectors/registry.py +900 -0
- configmanbearpig-2.0.0/src/openhound_sccm/collectors/smb.py +295 -0
- configmanbearpig-2.0.0/src/openhound_sccm/collectors/sms_rows.py +102 -0
- configmanbearpig-2.0.0/src/openhound_sccm/collectors/stubs.py +43 -0
- configmanbearpig-2.0.0/src/openhound_sccm/context.py +467 -0
- configmanbearpig-2.0.0/src/openhound_sccm/convert_pipeline.py +180 -0
- configmanbearpig-2.0.0/src/openhound_sccm/cve_table.py +201 -0
- configmanbearpig-2.0.0/src/openhound_sccm/edge_help.py +1520 -0
- configmanbearpig-2.0.0/src/openhound_sccm/extension.yaml +71 -0
- configmanbearpig-2.0.0/src/openhound_sccm/graph.py +965 -0
- configmanbearpig-2.0.0/src/openhound_sccm/integration/__init__.py +86 -0
- configmanbearpig-2.0.0/src/openhound_sccm/integration/fixtures/__init__.py +36 -0
- configmanbearpig-2.0.0/src/openhound_sccm/integration/fixtures/edges.py +799 -0
- configmanbearpig-2.0.0/src/openhound_sccm/integration/fixtures/nodes.py +185 -0
- configmanbearpig-2.0.0/src/openhound_sccm/kinds/__init__.py +0 -0
- configmanbearpig-2.0.0/src/openhound_sccm/kinds/edges.py +88 -0
- configmanbearpig-2.0.0/src/openhound_sccm/kinds/nodes.py +35 -0
- configmanbearpig-2.0.0/src/openhound_sccm/log_context.py +110 -0
- configmanbearpig-2.0.0/src/openhound_sccm/lookup.py +42 -0
- configmanbearpig-2.0.0/src/openhound_sccm/main.py +2188 -0
- configmanbearpig-2.0.0/src/openhound_sccm/models/__init__.py +25 -0
- configmanbearpig-2.0.0/src/openhound_sccm/models/computer.py +123 -0
- configmanbearpig-2.0.0/src/openhound_sccm/models/container.py +73 -0
- configmanbearpig-2.0.0/src/openhound_sccm/models/graph_edge.py +126 -0
- configmanbearpig-2.0.0/src/openhound_sccm/models/group.py +116 -0
- configmanbearpig-2.0.0/src/openhound_sccm/models/mssql_database.py +50 -0
- configmanbearpig-2.0.0/src/openhound_sccm/models/mssql_database_role.py +50 -0
- configmanbearpig-2.0.0/src/openhound_sccm/models/mssql_database_user.py +53 -0
- configmanbearpig-2.0.0/src/openhound_sccm/models/mssql_login.py +50 -0
- configmanbearpig-2.0.0/src/openhound_sccm/models/mssql_server.py +71 -0
- configmanbearpig-2.0.0/src/openhound_sccm/models/mssql_server_role.py +48 -0
- configmanbearpig-2.0.0/src/openhound_sccm/models/raw_table.py +81 -0
- configmanbearpig-2.0.0/src/openhound_sccm/models/sccm_admin_user.py +99 -0
- configmanbearpig-2.0.0/src/openhound_sccm/models/sccm_client_device.py +156 -0
- configmanbearpig-2.0.0/src/openhound_sccm/models/sccm_collection.py +90 -0
- configmanbearpig-2.0.0/src/openhound_sccm/models/sccm_security_role.py +87 -0
- configmanbearpig-2.0.0/src/openhound_sccm/models/sccm_site.py +134 -0
- configmanbearpig-2.0.0/src/openhound_sccm/models/stub_node.py +60 -0
- configmanbearpig-2.0.0/src/openhound_sccm/models/target_entry.py +25 -0
- configmanbearpig-2.0.0/src/openhound_sccm/models/user.py +102 -0
- configmanbearpig-2.0.0/src/openhound_sccm/opengraph_untagged.py +57 -0
- configmanbearpig-2.0.0/src/openhound_sccm/per_host_phases.py +124 -0
- configmanbearpig-2.0.0/src/openhound_sccm/phased_pipeline/__init__.py +30 -0
- configmanbearpig-2.0.0/src/openhound_sccm/phased_pipeline/engine.py +136 -0
- configmanbearpig-2.0.0/src/openhound_sccm/phased_pipeline/streams.py +27 -0
- configmanbearpig-2.0.0/src/openhound_sccm/phased_pipeline/work_queue.py +84 -0
- configmanbearpig-2.0.0/src/openhound_sccm/schema_MSSQL.json +264 -0
- configmanbearpig-2.0.0/src/openhound_sccm/schema_SCCM.json +184 -0
- configmanbearpig-2.0.0/src/openhound_sccm/source.py +327 -0
- configmanbearpig-2.0.0/src/openhound_sccm/transforms.py +5963 -0
- configmanbearpig-2.0.0/tests/__init__.py +0 -0
- configmanbearpig-2.0.0/tests/ab_matrix_test.py +94 -0
- configmanbearpig-2.0.0/tests/ad_auth_warnings_test.py +135 -0
- configmanbearpig-2.0.0/tests/ad_node_props_emit_test.py +146 -0
- configmanbearpig-2.0.0/tests/ad_props_derive_test.py +123 -0
- configmanbearpig-2.0.0/tests/ad_pth_ptt_test.py +26 -0
- configmanbearpig-2.0.0/tests/ad_resolver_attrs_test.py +17 -0
- configmanbearpig-2.0.0/tests/ad_test.py +158 -0
- configmanbearpig-2.0.0/tests/allowed_targets_test.py +33 -0
- configmanbearpig-2.0.0/tests/assumed_site_db_test.py +320 -0
- configmanbearpig-2.0.0/tests/clean_output_test.py +116 -0
- configmanbearpig-2.0.0/tests/cli_argument_warnings_test.py +55 -0
- configmanbearpig-2.0.0/tests/cli_option_panels_test.py +209 -0
- configmanbearpig-2.0.0/tests/client_device_extras_test.py +175 -0
- configmanbearpig-2.0.0/tests/coerce_smb_traversable_test.py +59 -0
- configmanbearpig-2.0.0/tests/collect_exit_code_test.py +19 -0
- configmanbearpig-2.0.0/tests/collect_run_all_test.py +255 -0
- configmanbearpig-2.0.0/tests/collect_summary_test.py +198 -0
- configmanbearpig-2.0.0/tests/collection_settings_test.py +8 -0
- configmanbearpig-2.0.0/tests/computer_test.py +107 -0
- configmanbearpig-2.0.0/tests/conftest.py +8 -0
- configmanbearpig-2.0.0/tests/convert_integration_test.py +228 -0
- configmanbearpig-2.0.0/tests/convert_pipeline_test.py +179 -0
- configmanbearpig-2.0.0/tests/convert_split_output_test.py +97 -0
- configmanbearpig-2.0.0/tests/convert_untagged_emit_test.py +61 -0
- configmanbearpig-2.0.0/tests/cve_table_test.py +49 -0
- configmanbearpig-2.0.0/tests/dc_only_flag_test.py +44 -0
- configmanbearpig-2.0.0/tests/debug_exc_info_filter_test.py +319 -0
- configmanbearpig-2.0.0/tests/dedup_client_device_test.py +88 -0
- configmanbearpig-2.0.0/tests/disable_possible_env_override_test.py +53 -0
- configmanbearpig-2.0.0/tests/dns_resolver_flag_test.py +189 -0
- configmanbearpig-2.0.0/tests/edge_all_permissions_test.py +86 -0
- configmanbearpig-2.0.0/tests/edge_assign_all_permissions_test.py +133 -0
- configmanbearpig-2.0.0/tests/edge_coerce_relay_adminservice_gate_test.py +73 -0
- configmanbearpig-2.0.0/tests/edge_coerce_relay_adminservice_test.py +63 -0
- configmanbearpig-2.0.0/tests/edge_coerce_relay_mssql_test.py +212 -0
- configmanbearpig-2.0.0/tests/edge_coerce_relay_smb_test.py +63 -0
- configmanbearpig-2.0.0/tests/edge_contains_test.py +20 -0
- configmanbearpig-2.0.0/tests/edge_has_client_test.py +16 -0
- configmanbearpig-2.0.0/tests/edge_has_member_test.py +64 -0
- configmanbearpig-2.0.0/tests/edge_has_session_test.py +28 -0
- configmanbearpig-2.0.0/tests/edge_has_stored_account_test.py +14 -0
- configmanbearpig-2.0.0/tests/edge_has_user_test.py +27 -0
- configmanbearpig-2.0.0/tests/edge_help_assumed_test.py +108 -0
- configmanbearpig-2.0.0/tests/edge_help_emit_test.py +77 -0
- configmanbearpig-2.0.0/tests/edge_help_integration_test.py +133 -0
- configmanbearpig-2.0.0/tests/edge_help_test.py +62 -0
- configmanbearpig-2.0.0/tests/edge_is_assigned_test.py +29 -0
- configmanbearpig-2.0.0/tests/edge_is_mapped_to_sccminfra_test.py +119 -0
- configmanbearpig-2.0.0/tests/edge_is_mapped_to_test.py +25 -0
- configmanbearpig-2.0.0/tests/edge_local_admin_required_test.py +139 -0
- configmanbearpig-2.0.0/tests/edge_member_of_test.py +24 -0
- configmanbearpig-2.0.0/tests/edge_mssql_membership_test.py +43 -0
- configmanbearpig-2.0.0/tests/edge_mssql_service_account_test.py +50 -0
- configmanbearpig-2.0.0/tests/edge_mssql_structural_test.py +74 -0
- configmanbearpig-2.0.0/tests/edge_rbac_role_grants_test.py +73 -0
- configmanbearpig-2.0.0/tests/edge_same_host_test.py +62 -0
- configmanbearpig-2.0.0/tests/enrich_client_device_ad_domain_sid_test.py +110 -0
- configmanbearpig-2.0.0/tests/extension_metadata_test.py +34 -0
- configmanbearpig-2.0.0/tests/extension_methods_test.py +49 -0
- configmanbearpig-2.0.0/tests/graph_edge_relay_props_test.py +47 -0
- configmanbearpig-2.0.0/tests/graph_edge_test.py +29 -0
- configmanbearpig-2.0.0/tests/graph_edges_coercion_cols_test.py +74 -0
- configmanbearpig-2.0.0/tests/graph_edges_dedup_test.py +75 -0
- configmanbearpig-2.0.0/tests/graph_edges_split_test.py +71 -0
- configmanbearpig-2.0.0/tests/graph_edges_test.py +100 -0
- configmanbearpig-2.0.0/tests/graph_mssql_props_test.py +56 -0
- configmanbearpig-2.0.0/tests/graph_test.py +35 -0
- configmanbearpig-2.0.0/tests/group_test.py +113 -0
- configmanbearpig-2.0.0/tests/http_auth_test.py +115 -0
- configmanbearpig-2.0.0/tests/http_cli_flags_test.py +33 -0
- configmanbearpig-2.0.0/tests/http_client_test.py +257 -0
- configmanbearpig-2.0.0/tests/http_negotiate_integration_test.py +84 -0
- configmanbearpig-2.0.0/tests/http_test.py +524 -0
- configmanbearpig-2.0.0/tests/http_version_probe_test.py +69 -0
- configmanbearpig-2.0.0/tests/impacket_noise_filter_test.py +63 -0
- configmanbearpig-2.0.0/tests/integration_cli_flags_test.py +121 -0
- configmanbearpig-2.0.0/tests/integration_fixtures_test.py +88 -0
- configmanbearpig-2.0.0/tests/integration_lowpriv_fixtures_test.py +242 -0
- configmanbearpig-2.0.0/tests/integration_privilege_test.py +66 -0
- configmanbearpig-2.0.0/tests/integration_wiring_test.py +53 -0
- configmanbearpig-2.0.0/tests/kinds_edges_mssql_test.py +24 -0
- configmanbearpig-2.0.0/tests/kinds_edges_stage6_test.py +21 -0
- configmanbearpig-2.0.0/tests/kinds_edges_test.py +27 -0
- configmanbearpig-2.0.0/tests/ldap_cmrc_site_code_test.py +26 -0
- configmanbearpig-2.0.0/tests/ldap_management_points_raw_test.py +247 -0
- configmanbearpig-2.0.0/tests/ldap_resolved_principals_test.py +261 -0
- configmanbearpig-2.0.0/tests/ldap_smc_recursion_test.py +278 -0
- configmanbearpig-2.0.0/tests/local_log_scrape_regex_test.py +113 -0
- configmanbearpig-2.0.0/tests/local_resources_state_test.py +189 -0
- configmanbearpig-2.0.0/tests/local_wmi_ccm_test.py +139 -0
- configmanbearpig-2.0.0/tests/lookup_test.py +25 -0
- configmanbearpig-2.0.0/tests/lowpriv_end_to_end_test.py +356 -0
- configmanbearpig-2.0.0/tests/models_main_import_test.py +4 -0
- configmanbearpig-2.0.0/tests/mssql_epa_test.py +119 -0
- configmanbearpig-2.0.0/tests/mssql_kerberoast_spn_test.py +87 -0
- configmanbearpig-2.0.0/tests/mssql_models_test.py +74 -0
- configmanbearpig-2.0.0/tests/mssql_scaffold_possible_test.py +243 -0
- configmanbearpig-2.0.0/tests/mssql_service_account_spn_test.py +72 -0
- configmanbearpig-2.0.0/tests/mssql_spn_host_test.py +79 -0
- configmanbearpig-2.0.0/tests/mssql_spn_service_account_test.py +244 -0
- configmanbearpig-2.0.0/tests/node_admin_user_test.py +115 -0
- configmanbearpig-2.0.0/tests/node_authenticated_users_test.py +94 -0
- configmanbearpig-2.0.0/tests/node_backfill_test.py +24 -0
- configmanbearpig-2.0.0/tests/node_client_device_possible_test.py +53 -0
- configmanbearpig-2.0.0/tests/node_client_device_test.py +75 -0
- configmanbearpig-2.0.0/tests/node_collection_test.py +58 -0
- configmanbearpig-2.0.0/tests/node_computer_smb_signing_source_test.py +49 -0
- configmanbearpig-2.0.0/tests/node_computer_test.py +489 -0
- configmanbearpig-2.0.0/tests/node_group_test.py +231 -0
- configmanbearpig-2.0.0/tests/node_mssql_database_test.py +26 -0
- configmanbearpig-2.0.0/tests/node_mssql_login_dbuser_test.py +78 -0
- configmanbearpig-2.0.0/tests/node_mssql_roles_test.py +54 -0
- configmanbearpig-2.0.0/tests/node_mssql_server_test.py +104 -0
- configmanbearpig-2.0.0/tests/node_security_role_test.py +93 -0
- configmanbearpig-2.0.0/tests/node_site_cve_test.py +15 -0
- configmanbearpig-2.0.0/tests/node_site_http_version_test.py +60 -0
- configmanbearpig-2.0.0/tests/node_site_test.py +282 -0
- configmanbearpig-2.0.0/tests/node_user_test.py +243 -0
- configmanbearpig-2.0.0/tests/orphaned_role_sources_test.py +197 -0
- configmanbearpig-2.0.0/tests/per_host_integration_test.py +168 -0
- configmanbearpig-2.0.0/tests/per_host_log_blocks_test.py +124 -0
- configmanbearpig-2.0.0/tests/per_host_phases_streams_test.py +42 -0
- configmanbearpig-2.0.0/tests/per_host_phases_test.py +66 -0
- configmanbearpig-2.0.0/tests/per_host_wiring_test.py +90 -0
- configmanbearpig-2.0.0/tests/possible_client_provenance_test.py +79 -0
- configmanbearpig-2.0.0/tests/pp_engine_test.py +258 -0
- configmanbearpig-2.0.0/tests/pp_streams_test.py +52 -0
- configmanbearpig-2.0.0/tests/pp_work_queue_test.py +110 -0
- configmanbearpig-2.0.0/tests/preproc_map_test.py +128 -0
- configmanbearpig-2.0.0/tests/principal_resolution_referral_test.py +79 -0
- configmanbearpig-2.0.0/tests/privileged_test.py +320 -0
- configmanbearpig-2.0.0/tests/privileged_user_group_test.py +59 -0
- configmanbearpig-2.0.0/tests/progress_option_test.py +34 -0
- configmanbearpig-2.0.0/tests/provenance_test.py +26 -0
- configmanbearpig-2.0.0/tests/proxy_dns_test.py +55 -0
- configmanbearpig-2.0.0/tests/proxy_integration_test.py +112 -0
- configmanbearpig-2.0.0/tests/proxy_wiring_test.py +73 -0
- configmanbearpig-2.0.0/tests/regen_ticket_index_test.py +109 -0
- configmanbearpig-2.0.0/tests/registry_access_denied_test.py +132 -0
- configmanbearpig-2.0.0/tests/registry_collect_test.py +512 -0
- configmanbearpig-2.0.0/tests/registry_current_user_test.py +27 -0
- configmanbearpig-2.0.0/tests/registry_test.py +18 -0
- configmanbearpig-2.0.0/tests/sccm_admin_user_test.py +86 -0
- configmanbearpig-2.0.0/tests/sccm_client_device_test.py +83 -0
- configmanbearpig-2.0.0/tests/sccm_collection_test.py +51 -0
- configmanbearpig-2.0.0/tests/sccm_possible_edges_lowpriv_test.py +136 -0
- configmanbearpig-2.0.0/tests/sccm_security_role_test.py +55 -0
- configmanbearpig-2.0.0/tests/sccm_site_test.py +161 -0
- configmanbearpig-2.0.0/tests/secondary_site_db_test.py +132 -0
- configmanbearpig-2.0.0/tests/sharphound_naming_test.py +409 -0
- configmanbearpig-2.0.0/tests/site_hierarchy_lowpriv_test.py +339 -0
- configmanbearpig-2.0.0/tests/site_system_roles_test.py +96 -0
- configmanbearpig-2.0.0/tests/site_type_inference_test.py +106 -0
- configmanbearpig-2.0.0/tests/smb_sso_integration_test.py +36 -0
- configmanbearpig-2.0.0/tests/smb_sso_test.py +437 -0
- configmanbearpig-2.0.0/tests/smb_test.py +243 -0
- configmanbearpig-2.0.0/tests/smc_container_test.py +119 -0
- configmanbearpig-2.0.0/tests/smc_memberof_test.py +65 -0
- configmanbearpig-2.0.0/tests/sms_rows_test.py +41 -0
- configmanbearpig-2.0.0/tests/stub_node_test.py +19 -0
- configmanbearpig-2.0.0/tests/stub_per_host_phases.py +37 -0
- configmanbearpig-2.0.0/tests/transforms_dc_only_test.py +76 -0
- configmanbearpig-2.0.0/tests/transforms_hardening_test.py +161 -0
- configmanbearpig-2.0.0/tests/transforms_lookups_test.py +32 -0
- configmanbearpig-2.0.0/tests/transforms_principal_test.py +49 -0
- configmanbearpig-2.0.0/tests/transforms_safe_fallback_test.py +213 -0
- configmanbearpig-2.0.0/tests/transforms_settings_test.py +39 -0
- configmanbearpig-2.0.0/tests/transforms_test.py +41 -0
- configmanbearpig-2.0.0/tests/user_test.py +96 -0
- configmanbearpig-2.0.0/tests/verbose_silent_flags_test.py +173 -0
- configmanbearpig-2.0.0/tests/wmi_client_test.py +175 -0
- configmanbearpig-2.0.0/uv.lock +1901 -0
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: grill-me
|
|
3
|
+
description: Interview the user relentlessly about a plan or design until reaching shared understanding, resolving each branch of the decision tree. Use when the user wants to stress-test a plan, get grilled on their design, or mentions "grill me".
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
Interview me relentlessly about every aspect of this plan until we reach a shared
|
|
7
|
+
understanding. Walk down each branch of the design tree, resolving dependencies between
|
|
8
|
+
decisions one-by-one. For each question, provide your recommended answer.
|
|
9
|
+
|
|
10
|
+
Ask the questions one at a time.
|
|
11
|
+
|
|
12
|
+
If a question can be answered by exploring the codebase, explore the codebase instead.
|
|
13
|
+
|
|
14
|
+
## Why this file exists separately
|
|
15
|
+
|
|
16
|
+
This skill used to live as a second YAML frontmatter block inside
|
|
17
|
+
`.agents/skills/openhound/SKILL.md`. A skill loader reads the *first* frontmatter block in
|
|
18
|
+
a file and ignores the rest, so `grill-me` never resolved — and because a missing skill
|
|
19
|
+
degrades to "no instructions" rather than an error, every agent asked to use it silently
|
|
20
|
+
improvised instead. One skill per file.
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: openhound
|
|
3
|
+
description: Use for all OpenHound collector work, including planning, graph schema, source collection, assets, lookup/preproc, registration, and validation.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# OpenHound Development Skill
|
|
7
|
+
|
|
8
|
+
Use this skill for any OpenHound collector task.
|
|
9
|
+
|
|
10
|
+
## Critical Rules (Always apply)
|
|
11
|
+
|
|
12
|
+
1. Read `.agents/standards/openhound.md` before editing collector code. This includes important standards and best practices for OpenHound collector development that are not repeated in the reference docs.
|
|
13
|
+
2. Based on the requested task, select the matching reference from the routing table. These contain specific rules and examples for different types of collector work.
|
|
14
|
+
3. For broad collector work, or when creating a new collector, read `.agents/standards/workflow.md`.
|
|
15
|
+
4. Important: Before finishing collector and graph behavior changes read `references/validate-extension.md`.
|
|
16
|
+
|
|
17
|
+
### Route By Task
|
|
18
|
+
|
|
19
|
+
| Task | Reference |
|
|
20
|
+
|---|---|
|
|
21
|
+
| Plan a new collector from API docs, sample responses, or requirements | `references/plan-collector.md` |
|
|
22
|
+
| Define graph base classes, common properties, node IDs, or edge properties | `references/graph-schema.md` |
|
|
23
|
+
| Register `collect`, `preproc`, `convert`, metadata, or entry points | `references/register-extension.md` |
|
|
24
|
+
| Implement API clients, auth, DLT resources, transformers, or secrets | `references/source-collection.md` |
|
|
25
|
+
| Add or modify models, node assets, edge assets, kind constants, or exports | `references/add-asset.md` |
|
|
26
|
+
| Add DuckDB transforms, lookup methods, lookup registration, or `self._lookup` usage | `references/preproc-lookup.md` |
|
|
27
|
+
| Validate collector changes before finishing | `references/validate-extension.md` |
|
|
28
|
+
|
|
29
|
+
### Routing Rules
|
|
30
|
+
|
|
31
|
+
- If the task touches multiple areas, read every matching reference.
|
|
32
|
+
- If adding or changing collector behavior, always read `references/validate-extension.md` before finishing.
|
|
33
|
+
- If the task involves a new collector or broad redesign, start with `references/plan-collector.md`.
|
|
34
|
+
- If models use `self._lookup`, also read `references/preproc-lookup.md` and `references/register-extension.md`.
|
|
35
|
+
- If adding a new collected resource, usually read `references/source-collection.md`, `references/add-asset.md`, and `references/validate-extension.md`.
|
|
36
|
+
|
|
37
|
+
---
|
|
38
|
+
name: grill-me
|
|
39
|
+
description: Interview the user relentlessly about a plan or design until reaching shared understanding, resolving each branch of the decision tree. Use when user wants to stress-test a plan, get grilled on their design, or mentions "grill me".
|
|
40
|
+
---
|
|
41
|
+
|
|
42
|
+
Interview me relentlessly about every aspect of this plan until we reach a shared understanding. Walk down each branch of the design tree, resolving dependencies between decisions one-by-one. For each question, provide your recommended answer.
|
|
43
|
+
|
|
44
|
+
Ask the questions one at a time.
|
|
45
|
+
|
|
46
|
+
If a question can be answered by exploring the codebase, explore the codebase instead.
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
# OpenHound Add Asset
|
|
2
|
+
|
|
3
|
+
Use this reference when adding a new resource model under `src/<pkg>/models/` or changing how a model emits nodes and edges.
|
|
4
|
+
|
|
5
|
+
## Files Usually Touched
|
|
6
|
+
|
|
7
|
+
- `src/<pkg>/models/<name>.py`
|
|
8
|
+
- `src/<pkg>/models/__init__.py`
|
|
9
|
+
- `src/<pkg>/kinds/nodes.py`
|
|
10
|
+
- `src/<pkg>/kinds/edges.py`
|
|
11
|
+
- `src/<pkg>/source.py`
|
|
12
|
+
- `src/<pkg>/main.py` if lookup/preproc table registration is required
|
|
13
|
+
- `src/<pkg>/transforms.py` and `src/<pkg>/lookup.py` if cross-table lookup is required
|
|
14
|
+
|
|
15
|
+
## Model Structure
|
|
16
|
+
|
|
17
|
+
Every collected asset should define two things:
|
|
18
|
+
|
|
19
|
+
1. A dataclass named `<Name>Properties` extending the extension base `<PREFIX>NodeProperties`.
|
|
20
|
+
2. A Pydantic `BaseAsset` subclass named `<Name>` decorated with `@app.asset(...)`.
|
|
21
|
+
|
|
22
|
+
The raw fields on the `BaseAsset` class should mirror the collected JSONL schema. The dataclass properties should describe the OpenGraph node properties emitted during conversion.
|
|
23
|
+
|
|
24
|
+
## Property Dataclasses
|
|
25
|
+
|
|
26
|
+
Every OpenGraph property field must be documented in the class docstring's `Attributes` section:
|
|
27
|
+
|
|
28
|
+
```python
|
|
29
|
+
from dataclasses import dataclass
|
|
30
|
+
|
|
31
|
+
from openhound_<pkg>.graph import EXNodeProperties
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
@dataclass
|
|
35
|
+
class AssetProperties(EXNodeProperties):
|
|
36
|
+
"""Properties for the Asset node.
|
|
37
|
+
|
|
38
|
+
Attributes:
|
|
39
|
+
hostname: The asset hostname.
|
|
40
|
+
"""
|
|
41
|
+
hostname: str
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Prefer nullable types over placeholder sentinels when data can be absent:
|
|
45
|
+
|
|
46
|
+
```python
|
|
47
|
+
group_name: str | None = None
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
Do not use empty strings to mean missing data unless the upstream API explicitly distinguishes empty string from null.
|
|
51
|
+
|
|
52
|
+
## Asset Classes
|
|
53
|
+
|
|
54
|
+
Use `@app.asset(...)` with `NodeDef` for node-bearing assets and `EdgeDef` for relationships emitted by that same class.
|
|
55
|
+
|
|
56
|
+
```python
|
|
57
|
+
from openhound.core.asset import BaseAsset, EdgeDef, NodeDef
|
|
58
|
+
from openhound.core.models.entries import Edge, EdgePath
|
|
59
|
+
|
|
60
|
+
from openhound_<pkg>.graph import EXNode
|
|
61
|
+
from openhound_<pkg>.kinds import edges as ek
|
|
62
|
+
from openhound_<pkg>.kinds import nodes as nk
|
|
63
|
+
from openhound_<pkg>.main import app
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
@app.asset(
|
|
67
|
+
node=NodeDef(kind=nk.ASSET, properties=AssetProperties, description="Example asset", icon="cog"),
|
|
68
|
+
edges=[
|
|
69
|
+
EdgeDef(
|
|
70
|
+
start=nk.ASSET,
|
|
71
|
+
end=nk.GROUP,
|
|
72
|
+
kind=ek.MEMBER_OF,
|
|
73
|
+
description="Asset belongs to group",
|
|
74
|
+
)
|
|
75
|
+
],
|
|
76
|
+
)
|
|
77
|
+
class Asset(BaseAsset):
|
|
78
|
+
id: str
|
|
79
|
+
name: str
|
|
80
|
+
groups: list[str]
|
|
81
|
+
|
|
82
|
+
@property
|
|
83
|
+
def as_node(self) -> EXNode:
|
|
84
|
+
properties = AssetProperties(
|
|
85
|
+
node_id=self.id,
|
|
86
|
+
name=self.name,
|
|
87
|
+
displayname=self.name,
|
|
88
|
+
environmentid=self._extras["environmentid"],
|
|
89
|
+
)
|
|
90
|
+
return EXNode(properties=properties, kinds=[nk.ASSET])
|
|
91
|
+
|
|
92
|
+
@property
|
|
93
|
+
def edges(self):
|
|
94
|
+
for group_id in self.groups:
|
|
95
|
+
yield Edge(
|
|
96
|
+
kind=ek.MEMBER_OF,
|
|
97
|
+
start=EdgePath(value=self.as_node.id, match_by="id"),
|
|
98
|
+
end=EdgePath(value=group_id, match_by="id"),
|
|
99
|
+
)
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
## Edge Definition Alignment
|
|
103
|
+
|
|
104
|
+
Only declare `EdgeDef(...)` entries on the asset class that emits those edges from its `edges` property.
|
|
105
|
+
|
|
106
|
+
If a node-bearing asset creates only a node, use only `node=NodeDef(...)` and emit no edges. If relationships are represented by a separate edge-only asset, put the `EdgeDef(...)` declarations on that edge-only asset.
|
|
107
|
+
|
|
108
|
+
If a helper emits a shared edge, such as a root/environment containment edge, declare the matching `EdgeDef(...)` on every asset that yields it.
|
|
109
|
+
|
|
110
|
+
## Edge Emission Style
|
|
111
|
+
|
|
112
|
+
Prefer generators:
|
|
113
|
+
|
|
114
|
+
```python
|
|
115
|
+
@property
|
|
116
|
+
def _access_edges(self):
|
|
117
|
+
for target_id in self.target_ids:
|
|
118
|
+
yield Edge(...)
|
|
119
|
+
|
|
120
|
+
@property
|
|
121
|
+
def edges(self):
|
|
122
|
+
yield from self._access_edges
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
Avoid building `edges = []`, appending items, and returning the list unless there is a specific reason.
|
|
126
|
+
|
|
127
|
+
## Conditional Edge Paths
|
|
128
|
+
|
|
129
|
+
Prefer `ConditionalEdgePath` when creating an edge to an existing node that should be resolved by node properties instead of a known OpenGraph ID.
|
|
130
|
+
|
|
131
|
+
Use `PropertyMatch` entries for the stable property constraints needed to uniquely identify the target node. Avoid weak matchers, such as only `name`, unless the upstream domain guarantees uniqueness.
|
|
132
|
+
|
|
133
|
+
Use `EdgePath(value=..., match_by="id")` when the exact stable node ID is already known.
|
|
134
|
+
|
|
135
|
+
```python
|
|
136
|
+
from openhound.core.models.entries import ConditionalEdgePath, Edge, EdgePath, PropertyMatch
|
|
137
|
+
from openhound.core.models.entries_dataclass import EdgeProperties
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
yield Edge(
|
|
141
|
+
kind=ek.MEMBERSHIP_SYNC,
|
|
142
|
+
start=ConditionalEdgePath(
|
|
143
|
+
kind=nk.GROUP,
|
|
144
|
+
property_matchers=[
|
|
145
|
+
PropertyMatch(key="tenant_domain", value=source_domain),
|
|
146
|
+
PropertyMatch(key="type", value="OKTA_GROUP"),
|
|
147
|
+
PropertyMatch(key="name", value=self.profile.name.upper()),
|
|
148
|
+
],
|
|
149
|
+
),
|
|
150
|
+
end=EdgePath(value=self.id, match_by="id"),
|
|
151
|
+
properties=EdgeProperties(traversable=True),
|
|
152
|
+
)
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
## Lookup Usage
|
|
156
|
+
|
|
157
|
+
Use `self._lookup` inside `as_node` or `edges` only when `preproc` creates and registers the required lookup data.
|
|
158
|
+
|
|
159
|
+
```python
|
|
160
|
+
@property
|
|
161
|
+
def as_node(self) -> EXNode:
|
|
162
|
+
org_node_id = self._lookup.org_id_for(self.org_name)
|
|
163
|
+
properties = AssetProperties(node_id=self.id, org_id=org_node_id)
|
|
164
|
+
return EXNode(properties=properties, kinds=[nk.ASSET])
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
## Checklist
|
|
168
|
+
|
|
169
|
+
- Create or update `src/<pkg>/models/<name>.py`.
|
|
170
|
+
- Add node kind constants to `kinds/nodes.py` if the asset emits nodes.
|
|
171
|
+
- Add edge kind constants to `kinds/edges.py` if the asset emits edges.
|
|
172
|
+
- Assets returning a node must pass the emitted property dataclass into `NodeDef(properties=...)`.
|
|
173
|
+
- Export the model from `src/<pkg>/models/__init__.py`.
|
|
174
|
+
- Add or update a resource or transformer in `source.py`.
|
|
175
|
+
- Wire the resource or transformer into the source return tuple.
|
|
176
|
+
- If lookup data is needed, update `transforms.py`, `lookup.py`, and the `preproc` table map in `main.py`.
|
|
177
|
+
- Read `references/validate-extension.md` before finishing.
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
# OpenHound Graph Schema
|
|
2
|
+
|
|
3
|
+
Use this reference when editing `src/<pkg>/graph.py` or changing extension-wide OpenGraph node and edge property behavior.
|
|
4
|
+
|
|
5
|
+
## Purpose
|
|
6
|
+
|
|
7
|
+
`graph.py` defines the OpenHound extension's base dataclass types for nodes, node properties, and edge properties. These types are imported by model files and lookup-related code.
|
|
8
|
+
|
|
9
|
+
## Naming
|
|
10
|
+
|
|
11
|
+
Use the extension prefix consistently:
|
|
12
|
+
|
|
13
|
+
- `<PREFIX>NodeProperties`
|
|
14
|
+
- `<PREFIX>Node`
|
|
15
|
+
- `<PREFIX>EdgeProperties`
|
|
16
|
+
|
|
17
|
+
For example, GitHub might use `GHNodeProperties`, `GHNode`, and `GHEdgeProperties`.
|
|
18
|
+
|
|
19
|
+
## Base Node Properties
|
|
20
|
+
|
|
21
|
+
The base properties class should extend `NodeProperties` from `openhound.core.models.entries_dataclass`.
|
|
22
|
+
|
|
23
|
+
Add only fields that every node in the extension should have.
|
|
24
|
+
|
|
25
|
+
```python
|
|
26
|
+
from dataclasses import dataclass
|
|
27
|
+
|
|
28
|
+
from openhound.core.models.entries_dataclass import NodeProperties as BaseProperties
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
@dataclass
|
|
32
|
+
class EXNodeProperties(BaseProperties):
|
|
33
|
+
"""Base properties for all nodes in the extension.
|
|
34
|
+
|
|
35
|
+
Attributes:
|
|
36
|
+
node_id: The platform native unique identifier.
|
|
37
|
+
"""
|
|
38
|
+
node_id: str
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
Every field must include docstrings specifying the attributes with a description because this is used for generated documentation.
|
|
42
|
+
|
|
43
|
+
Every collector should have one root/environment node. When a collector emits multiple resource nodes, include `environmentid` in the base node properties and set it to the OpenGraph ID of that root/environment node.
|
|
44
|
+
|
|
45
|
+
## Node Class
|
|
46
|
+
|
|
47
|
+
The node class should extend `Node` from `openhound.core.models.entries_dataclass` and set `self.id` in `__post_init__`.
|
|
48
|
+
|
|
49
|
+
```python
|
|
50
|
+
from dataclasses import dataclass, field
|
|
51
|
+
|
|
52
|
+
from openhound.core.models.entries_dataclass import Node as BaseNode
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
@dataclass
|
|
56
|
+
class EXNode(BaseNode):
|
|
57
|
+
properties: EXNodeProperties
|
|
58
|
+
kinds: list[str]
|
|
59
|
+
id: str = field(init=False)
|
|
60
|
+
|
|
61
|
+
def __post_init__(self):
|
|
62
|
+
self.id = self.properties.node_id
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
## Node ID Rules
|
|
66
|
+
|
|
67
|
+
Prefer the platform's native opaque/global node ID when available and only when the native ID is consistent and unique.
|
|
68
|
+
|
|
69
|
+
Do not use raw integer primary keys as OpenGraph node IDs. They are not stable enough across systems and can collide across extensions.
|
|
70
|
+
|
|
71
|
+
If the platform does not expose a suitable ID, derive one from stable properties with `BaseNode.guid(...)`:
|
|
72
|
+
|
|
73
|
+
```python
|
|
74
|
+
def __post_init__(self):
|
|
75
|
+
self.id = self.guid(self.properties.tenant_id, self.properties.slug)
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
Use reproducible values only. Do not include timestamps, random values, pagination offsets or mutable display names unless they are the best stable identifier the service provides.
|
|
79
|
+
|
|
80
|
+
## Edge Properties
|
|
81
|
+
|
|
82
|
+
The extension edge property class should extend `EdgeProperties`.
|
|
83
|
+
|
|
84
|
+
```python
|
|
85
|
+
from dataclasses import dataclass
|
|
86
|
+
|
|
87
|
+
from openhound.core.models.entries_dataclass import EdgeProperties
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
@dataclass
|
|
91
|
+
class EXEdgeProperties(EdgeProperties):
|
|
92
|
+
reason: str | None = None
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
Add shared fields only when they apply broadly across extension edges. Entity-specific relationship fields can stay closer to the emitting model when appropriate.
|
|
96
|
+
|
|
97
|
+
## Graph Schema Rules
|
|
98
|
+
|
|
99
|
+
- Keep `graph.py` generic to the extension, not specific to one entity.
|
|
100
|
+
- Avoid importing model classes into `graph.py`.
|
|
101
|
+
- Avoid importing `app` into `graph.py`.
|
|
102
|
+
- Do not define kind strings in `graph.py`; use `kinds/nodes.py` and `kinds/edges.py`.
|
|
103
|
+
- Do not add compatibility aliases unless there is persisted data, shipped behavior, external consumers, or an explicit requirement.
|
|
104
|
+
|
|
105
|
+
## Checklist
|
|
106
|
+
|
|
107
|
+
- Prefix classes match the service prefix.
|
|
108
|
+
- Base node properties extend the OpenHound base properties class.
|
|
109
|
+
- Node class extends the OpenHound base node class.
|
|
110
|
+
- `id` is assigned in `__post_init__`.
|
|
111
|
+
- Node ID is stable and string-compatible.
|
|
112
|
+
- Base node properties include `environmentid` when the collector emits a root/environment node.
|
|
113
|
+
- Every graph property contains docstrings with an "Attributes" section describing each field.
|
|
114
|
+
- Read `references/validate-extension.md` before finishing.
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
# OpenHound Plan Collector
|
|
2
|
+
|
|
3
|
+
Use this reference before implementing a new collector or making broad collector changes. The output should be a concise design brief that maps the target service into OpenHound resources, graph nodes, edges, and follow-up implementation references.
|
|
4
|
+
|
|
5
|
+
Do not implement collection, models, lookup logic, or metadata from this reference. Use it to decide what should be built and in what order.
|
|
6
|
+
|
|
7
|
+
## Inputs To Gather
|
|
8
|
+
|
|
9
|
+
- Target service name, slug, and intended short graph prefix.
|
|
10
|
+
- Authentication method, required credentials, and non-secret configuration values.
|
|
11
|
+
- API base URL, versioning model, pagination style, rate limits, and retry behavior.
|
|
12
|
+
- Primary resources to collect, such as users, groups, devices, roles, policies, repositories, or memberships.
|
|
13
|
+
- Sample API responses or schema references for each resource.
|
|
14
|
+
- Stable identifiers for each resource.
|
|
15
|
+
- Relationships between resources and whether they can be emitted directly or need lookup/preproc.
|
|
16
|
+
- Any sensitive fields that should not be collected or emitted.
|
|
17
|
+
- Expected commands or environments used to validate the collector.
|
|
18
|
+
|
|
19
|
+
If required information is missing, ask focused questions before designing implementation details.
|
|
20
|
+
|
|
21
|
+
## Planning Checklist
|
|
22
|
+
|
|
23
|
+
### 1. Service Identity
|
|
24
|
+
|
|
25
|
+
Define the collector identity:
|
|
26
|
+
|
|
27
|
+
- Source name and source_kind used by `OpenHound("<source>", source_kind=<kind>)`.
|
|
28
|
+
- Python package name, normally `openhound_<source>`.
|
|
29
|
+
- Short uppercase graph prefix, usually two to four characters.
|
|
30
|
+
- Extension metadata values for `extension.yaml`.
|
|
31
|
+
|
|
32
|
+
### 2. Credentials And Configuration
|
|
33
|
+
|
|
34
|
+
List required secrets and parameters:
|
|
35
|
+
|
|
36
|
+
- DLT secret names expected under `[sources.source.<source>]`.
|
|
37
|
+
- Environment variable equivalents where useful.
|
|
38
|
+
- Non-secret parameters such as tenant, organization, region, or API host.
|
|
39
|
+
- Whether a dedicated `auth.py` module is likely needed.
|
|
40
|
+
|
|
41
|
+
### 3. Resources To Collect
|
|
42
|
+
|
|
43
|
+
Create a resource inventory:
|
|
44
|
+
|
|
45
|
+
| Resource | API endpoint | DLT table | Model | Notes |
|
|
46
|
+
|---|---|---|---|---|
|
|
47
|
+
| users | `/users` | `users` | `User` | Example top-level resource. |
|
|
48
|
+
|
|
49
|
+
For each resource, decide whether it should be a top-level `@app.resource` or a nested `@app.transformer`.
|
|
50
|
+
|
|
51
|
+
### 4. Graph Shape
|
|
52
|
+
|
|
53
|
+
Create a graph inventory:
|
|
54
|
+
|
|
55
|
+
| Node | Kind constant | Source resource | Stable ID | Notes |
|
|
56
|
+
|---|---|---|---|---|
|
|
57
|
+
| User | `USER` | `users` | Native user ID | Example node. |
|
|
58
|
+
|
|
59
|
+
Include one root/environment node for the collected environment. Other emitted nodes should set `environmentid` to that node's OpenGraph ID.
|
|
60
|
+
|
|
61
|
+
| Edge | Start | End | Source resource | Lookup needed |
|
|
62
|
+
|---|---|---|---|---|
|
|
63
|
+
| `MEMBER_OF` | User | Group | memberships | No |
|
|
64
|
+
|
|
65
|
+
Prefer native opaque/global IDs when available. Do not plan raw integer primary keys as OpenGraph node IDs unless they are converted into stable, collision-resistant IDs.
|
|
66
|
+
|
|
67
|
+
### 5. Lookup And Preproc Needs
|
|
68
|
+
|
|
69
|
+
Identify where direct conversion is not enough:
|
|
70
|
+
|
|
71
|
+
- Relationships requiring joins across collected tables.
|
|
72
|
+
- Display or context fields that need enrichment from another table.
|
|
73
|
+
- Derived tables that should be created in `transforms.py`.
|
|
74
|
+
- Lookup methods that should be cached in `lookup.py`.
|
|
75
|
+
|
|
76
|
+
If no cross-table resolution is needed, explicitly say preproc/lookup is not required.
|
|
77
|
+
|
|
78
|
+
### 6. Implementation Order
|
|
79
|
+
|
|
80
|
+
Map the plan to references:
|
|
81
|
+
|
|
82
|
+
1. `references/graph-schema.md` for graph base types and ID strategy.
|
|
83
|
+
2. `references/register-extension.md` for phase registration and metadata.
|
|
84
|
+
3. `references/source-collection.md` for API resources and transformers.
|
|
85
|
+
4. `references/add-asset.md` for each model, node, edge, and kind constant.
|
|
86
|
+
5. `references/preproc-lookup.md` only when cross-table lookup is required.
|
|
87
|
+
6. `references/validate-extension.md` before finishing.
|
|
88
|
+
|
|
89
|
+
## Output Format
|
|
90
|
+
|
|
91
|
+
Produce a short collector design brief:
|
|
92
|
+
|
|
93
|
+
```markdown
|
|
94
|
+
# Collector Plan: <Service>
|
|
95
|
+
|
|
96
|
+
## Assumptions
|
|
97
|
+
- <assumption or question>
|
|
98
|
+
|
|
99
|
+
## Credentials And Parameters
|
|
100
|
+
- <secret or parameter>
|
|
101
|
+
|
|
102
|
+
## Resources
|
|
103
|
+
| Resource | API endpoint | DLT table | Model | Type |
|
|
104
|
+
|---|---|---|---|---|
|
|
105
|
+
|
|
106
|
+
## Graph
|
|
107
|
+
| Node | Kind | Stable ID | Source |
|
|
108
|
+
|---|---|---|---|
|
|
109
|
+
|
|
110
|
+
| Edge | Start | End | Source | Lookup needed |
|
|
111
|
+
|---|---|---|---|---|
|
|
112
|
+
|
|
113
|
+
## Preproc And Lookup
|
|
114
|
+
- <needed/not needed and why>
|
|
115
|
+
|
|
116
|
+
## Implementation Sequence
|
|
117
|
+
1. <reference and concrete target>
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
Keep the brief practical. Avoid speculative resources, edges, or abstractions that are not supported by the target service requirements or API data.
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
# OpenHound Preproc And Lookup
|
|
2
|
+
|
|
3
|
+
Use this reference when relationships or node properties require data from multiple collected tables.
|
|
4
|
+
|
|
5
|
+
## Purpose
|
|
6
|
+
|
|
7
|
+
`preproc` loads selected raw JSONL tables into DuckDB, runs optional SQL transforms and produces lookup data used during `convert` through `self._lookup`.
|
|
8
|
+
|
|
9
|
+
Use this path when a model needs to resolve information that is not present in its own raw row.
|
|
10
|
+
|
|
11
|
+
## Files Usually Touched
|
|
12
|
+
|
|
13
|
+
- `src/<pkg>/transforms.py`
|
|
14
|
+
- `src/<pkg>/lookup.py`
|
|
15
|
+
- `src/<pkg>/main.py`
|
|
16
|
+
- `src/<pkg>/models/<name>.py`
|
|
17
|
+
- `src/<pkg>/source.py` if new raw tables must be collected
|
|
18
|
+
|
|
19
|
+
## Transforms
|
|
20
|
+
|
|
21
|
+
`transforms.py` should contain plain DuckDB SQL functions. Keep each transform focused and call them from a top-level `transforms` function.
|
|
22
|
+
|
|
23
|
+
```python
|
|
24
|
+
import duckdb
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def create_joined_tables(con: duckdb.DuckDBPyConnection, schema: str = "myservice") -> None:
|
|
28
|
+
con.execute(
|
|
29
|
+
f"""
|
|
30
|
+
CREATE OR REPLACE TABLE {schema}.asset_groups AS
|
|
31
|
+
SELECT asset_id, group_id
|
|
32
|
+
FROM {schema}.asset_memberships
|
|
33
|
+
"""
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def transforms(con: duckdb.DuckDBPyConnection, schema: str = "myservice") -> None:
|
|
38
|
+
create_joined_tables(con, schema)
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
Use parameter binding for values. Schema and table names are often interpolated because DuckDB does not bind identifiers; keep those values internal and trusted.
|
|
42
|
+
|
|
43
|
+
Use DuckDB JSON operators for JSON object fields loaded from raw resources:
|
|
44
|
+
|
|
45
|
+
```sql
|
|
46
|
+
SELECT metadata->>'name' AS name
|
|
47
|
+
FROM myservice.assets
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## Preproc Registration
|
|
51
|
+
|
|
52
|
+
The `preproc` function in `main.py` returns a mapping of DuckDB table name to JSONL table name. Only listed tables are loaded into the lookup DB.
|
|
53
|
+
|
|
54
|
+
```python
|
|
55
|
+
@app.preproc(transformer=transforms)
|
|
56
|
+
def preproc(ctx: PreProcContext) -> dict[str, str]:
|
|
57
|
+
return {
|
|
58
|
+
"assets": "assets",
|
|
59
|
+
"asset_memberships": "asset_memberships",
|
|
60
|
+
}
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
If no SQL transforms are needed, the transformer can be omitted. If lookup methods depend on transformed tables, ensure the transformer is registered.
|
|
64
|
+
|
|
65
|
+
If `lookup.py` reads a table created by `transforms.py`, use `@app.preproc(transformer=transforms)`.
|
|
66
|
+
|
|
67
|
+
## Lookup Manager
|
|
68
|
+
|
|
69
|
+
`lookup.py` should define one extension lookup class extending `LookupManager`. Use `@lru_cache` for repeated lookups.
|
|
70
|
+
|
|
71
|
+
```python
|
|
72
|
+
from functools import lru_cache
|
|
73
|
+
|
|
74
|
+
from openhound.core.lookup import LookupManager
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
class EXLookup(LookupManager):
|
|
78
|
+
|
|
79
|
+
def __init__(self, client: DuckDBPyConnection, schema: str = "myservice"):
|
|
80
|
+
super().__init__(client, schema)
|
|
81
|
+
self.schema = schema
|
|
82
|
+
self.client = client
|
|
83
|
+
|
|
84
|
+
@lru_cache
|
|
85
|
+
def group_id_for(self, name: str) -> str | None:
|
|
86
|
+
return self._find_single_object(
|
|
87
|
+
f"SELECT node_id FROM {self.schema}.groups WHERE name = ?",
|
|
88
|
+
[name],
|
|
89
|
+
)
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
@lru_cache
|
|
93
|
+
def all_assets_domain(self, domain: str) -> list:
|
|
94
|
+
return self._find_all_objects(
|
|
95
|
+
f"SELECT * FROM {self.schema}.assets WHERE domain = ?",
|
|
96
|
+
[domain],
|
|
97
|
+
)
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
Prefer small lookup methods with clear names. The `_find_single_object` method will return `None` if no results are found.
|
|
101
|
+
|
|
102
|
+
## Convert Registration
|
|
103
|
+
|
|
104
|
+
Register the lookup class on `@app.convert(...)`:
|
|
105
|
+
|
|
106
|
+
```python
|
|
107
|
+
@app.convert(lookup=EXLookup)
|
|
108
|
+
def convert(ctx: ConvertContext) -> DltSource:
|
|
109
|
+
from .source import source as myservice_source
|
|
110
|
+
|
|
111
|
+
return myservice_source(), {}
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
The lookup is injected into each `BaseAsset` as `self._lookup` during convert.
|
|
115
|
+
|
|
116
|
+
## Model Usage
|
|
117
|
+
|
|
118
|
+
Use lookup methods from `as_node` or `edges` when needed:
|
|
119
|
+
|
|
120
|
+
```python
|
|
121
|
+
@property
|
|
122
|
+
def edges(self):
|
|
123
|
+
group_id = self._lookup.group_id_for(self.group_name)
|
|
124
|
+
if group_id is None:
|
|
125
|
+
return
|
|
126
|
+
|
|
127
|
+
yield Edge(
|
|
128
|
+
kind=ek.MEMBER_OF,
|
|
129
|
+
start=EdgePath(value=self.as_node.id, match_by="id"),
|
|
130
|
+
end=EdgePath(value=group_id, match_by="id"),
|
|
131
|
+
)
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
Document in the collector README when users must run `preproc` before `convert`.
|
|
135
|
+
|
|
136
|
+
## Rules
|
|
137
|
+
|
|
138
|
+
- Do not call `self._lookup` unless `convert` is registered with the lookup class.
|
|
139
|
+
- Do not assume raw tables are available in DuckDB unless they are returned by `preproc`.
|
|
140
|
+
- Keep transform output table names stable; lookup methods may depend on them.
|
|
141
|
+
- Avoid loading unnecessary raw tables into preproc.
|
|
142
|
+
- Cache deterministic lookup methods with `@lru_cache` or `@cache`.
|
|
143
|
+
|
|
144
|
+
## Checklist
|
|
145
|
+
|
|
146
|
+
- Required raw tables are collected by `source.py` and match with the defined resource/transformer name.
|
|
147
|
+
- Required raw tables are included in `main.py`'s `preproc` mapping.
|
|
148
|
+
- SQL transforms create any derived tables used by lookup methods.
|
|
149
|
+
- `@app.preproc(transformer=transforms)` is used when transforms are required.
|
|
150
|
+
- `@app.preproc(transformer=transforms)` is used when lookup reads transformed tables.
|
|
151
|
+
- `lookup.py` contains cached lookup methods.
|
|
152
|
+
- `@app.convert(lookup=<PREFIX>Lookup)` is registered.
|
|
153
|
+
- Models handle missing lookup results.
|
|
154
|
+
- Read `references/validate-extension.md` before finishing.
|