procesio-cli 0.1.1__py3-none-any.whl
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.
- procesio_cli/__init__.py +18 -0
- procesio_cli/_cli.py +71 -0
- procesio_cli/agents/__init__.py +0 -0
- procesio_cli/agents/_lib/__init__.py +0 -0
- procesio_cli/agents/_lib/actiondef.py +24 -0
- procesio_cli/agents/_lib/errors.py +40 -0
- procesio_cli/agents/_lib/reversibility.py +236 -0
- procesio_cli/agents/_lib/toolrunner.py +141 -0
- procesio_cli/agents/connector-builder/CONNECTOR-BUILDER-PLAYBOOK.md +62 -0
- procesio_cli/agents/connector-builder/CONNECTOR-BUILDER-PROCESIO-INTEROP.md +76 -0
- procesio_cli/agents/connector-builder/CONNECTOR-BUILDER-TROUBLESHOOTING.md +60 -0
- procesio_cli/agents/connector-builder/README.md +51 -0
- procesio_cli/agents/connector-builder/agent.yaml +61 -0
- procesio_cli/agents/connector-builder/context.py +19 -0
- procesio_cli/agents/connector-builder/handlers/__init__.py +1 -0
- procesio_cli/agents/connector-builder/handlers/checklist.py +71 -0
- procesio_cli/agents/connector-builder/handlers/guidance.py +37 -0
- procesio_cli/agents/connector-builder/handlers/nextstep.py +221 -0
- procesio_cli/agents/connector-builder/handlers/status.py +35 -0
- procesio_cli/agents/connector-builder/knowledge.py +47 -0
- procesio_cli/agents/connector-builder/main.py +93 -0
- procesio_cli/agents/connector-builder/tests/conftest.py +95 -0
- procesio_cli/agents/connector-builder/tests/test_cba_agent.py +148 -0
- procesio_cli/agents/orchestrator/__init__.py +0 -0
- procesio_cli/agents/orchestrator/bootstraplib.py +166 -0
- procesio_cli/agents/procesio/IMPLEMENTATION-PATTERNS/00-INDEX.md +60 -0
- procesio_cli/agents/procesio/IMPLEMENTATION-PATTERNS/01-PROCESSES.md +230 -0
- procesio_cli/agents/procesio/IMPLEMENTATION-PATTERNS/02-FORMS.md +287 -0
- procesio_cli/agents/procesio/IMPLEMENTATION-PATTERNS/03-INTEGRATIONS.md +384 -0
- procesio_cli/agents/procesio/IMPLEMENTATION-PATTERNS/04-DATABASE.md +293 -0
- procesio_cli/agents/procesio/PROCESIO-API-RELIABILITY-DOCTRINE.md +113 -0
- procesio_cli/agents/procesio/PROCESIO-BEST-PRACTICES.md +316 -0
- procesio_cli/agents/procesio/PROCESIO-BUILD-AND-TEST-PLAYBOOK.md +217 -0
- procesio_cli/agents/procesio/PROCESIO-DATASTORE.md +72 -0
- procesio_cli/agents/procesio/PROCESIO-ENVIRONMENTS.md +62 -0
- procesio_cli/agents/procesio/PROCESIO-SCHEDULING.md +47 -0
- procesio_cli/agents/procesio/PROCESIO-VISUAL-ORGANIZATION.md +175 -0
- procesio_cli/agents/procesio/README.md +97 -0
- procesio_cli/agents/procesio/__init__.py +0 -0
- procesio_cli/agents/procesio/agent.yaml +73 -0
- procesio_cli/agents/procesio/audit.py +226 -0
- procesio_cli/agents/procesio/checklist.py +135 -0
- procesio_cli/agents/procesio/context.py +19 -0
- procesio_cli/agents/procesio/handlers/__init__.py +0 -0
- procesio_cli/agents/procesio/handlers/audit.py +39 -0
- procesio_cli/agents/procesio/handlers/checklist.py +34 -0
- procesio_cli/agents/procesio/handlers/guidance.py +36 -0
- procesio_cli/agents/procesio/handlers/status.py +33 -0
- procesio_cli/agents/procesio/handlers/verify.py +39 -0
- procesio_cli/agents/procesio/knowledge.py +115 -0
- procesio_cli/agents/procesio/main.py +89 -0
- procesio_cli/agents/procesio/tests/__init__.py +0 -0
- procesio_cli/agents/procesio/tests/conftest.py +62 -0
- procesio_cli/agents/procesio/tests/test_audit.py +91 -0
- procesio_cli/agents/procesio/tests/test_checklist.py +28 -0
- procesio_cli/agents/procesio/tests/test_guidance.py +78 -0
- procesio_cli/agents/procesio/tests/test_manifest_sync.py +48 -0
- procesio_cli/agents/procesio/tests/test_verify.py +134 -0
- procesio_cli/agents/procesio/tests/test_workspace_scope.py +97 -0
- procesio_cli/agents/procesio/verifylib.py +222 -0
- procesio_cli/dashboard/README.md +117 -0
- procesio_cli/dashboard/__init__.py +18 -0
- procesio_cli/dashboard/serve.py +98 -0
- procesio_cli/dashboard/server/__init__.py +1 -0
- procesio_cli/dashboard/server/config_schemas.py +92 -0
- procesio_cli/dashboard/server/google.py +103 -0
- procesio_cli/dashboard/server/handler.py +160 -0
- procesio_cli/dashboard/server/inventory.py +213 -0
- procesio_cli/dashboard/server/jobs.py +118 -0
- procesio_cli/dashboard/server/llmtest.py +181 -0
- procesio_cli/dashboard/server/procesio_env.py +94 -0
- procesio_cli/dashboard/server/routes.py +74 -0
- procesio_cli/dashboard/server/runner.py +150 -0
- procesio_cli/dashboard/server/security.py +29 -0
- procesio_cli/dashboard/server/setup.py +211 -0
- procesio_cli/dashboard/server/validate.py +152 -0
- procesio_cli/dashboard/tests/conftest.py +16 -0
- procesio_cli/dashboard/tests/test_dashboard.py +225 -0
- procesio_cli/dashboard/tests/test_procesio_env.py +159 -0
- procesio_cli/dashboard/web/actions.js +274 -0
- procesio_cli/dashboard/web/api.js +79 -0
- procesio_cli/dashboard/web/app.js +385 -0
- procesio_cli/dashboard/web/copilot.js +72 -0
- procesio_cli/dashboard/web/google.js +121 -0
- procesio_cli/dashboard/web/index.html +67 -0
- procesio_cli/dashboard/web/procesio_env.js +187 -0
- procesio_cli/dashboard/web/styles.css +207 -0
- procesio_cli/registry.py +370 -0
- procesio_cli/scripts/build-router.py +249 -0
- procesio_cli/scripts/build-tool-skill.py +202 -0
- procesio_cli/scripts/check-requirements.py +131 -0
- procesio_cli/scripts/check-skill-governance.py +174 -0
- procesio_cli/scripts/evaluate-skill-routing.py +217 -0
- procesio_cli/scripts/evaluate-skills.py +316 -0
- procesio_cli/scripts/get-skill.py +122 -0
- procesio_cli/scripts/list-skills.py +68 -0
- procesio_cli/scripts/list-tools.py +73 -0
- procesio_cli/scripts/run-agent.py +59 -0
- procesio_cli/scripts/run-tool.py +123 -0
- procesio_cli/scripts/secret_scan.py +584 -0
- procesio_cli/scripts/set-credential.py +126 -0
- procesio_cli/scripts/validate-skills.py +530 -0
- procesio_cli/skills/PORTFOLIO.md +134 -0
- procesio_cli/skills/__init__.py +6 -0
- procesio_cli/skills/agent-skill-engineer/SKILL.md +226 -0
- procesio_cli/skills/agent-skill-engineer/evals/evals.json +422 -0
- procesio_cli/skills/agent-skill-engineer/references/authoring-standard.md +178 -0
- procesio_cli/skills/agent-skill-engineer/references/decision-framework.md +107 -0
- procesio_cli/skills/agent-skill-engineer/references/domain-evidence-protocol.md +248 -0
- procesio_cli/skills/agent-skill-engineer/references/evaluation-standard.md +191 -0
- procesio_cli/skills/agent-skill-engineer/references/expert-lenses.md +167 -0
- procesio_cli/skills/agent-skill-engineer/references/field-gate-standard.md +231 -0
- procesio_cli/skills/agent-skill-engineer/references/optimization-protocol.md +233 -0
- procesio_cli/skills/agent-skill-engineer/references/optimizer-contract.md +268 -0
- procesio_cli/skills/agent-skill-engineer/references/portability-standard.md +99 -0
- procesio_cli/skills/agent-skill-engineer/references/research-basis.md +128 -0
- procesio_cli/skills/agent-skill-engineer/references/review-standard.md +143 -0
- procesio_cli/skills/agent-skill-engineer/scripts/audit_skill.py +959 -0
- procesio_cli/skills/agent-skill-engineer/scripts/optimize_skill.py +891 -0
- procesio_cli/skills/agent-skill-engineer/scripts/scaffold_skill.py +397 -0
- procesio_cli/skills/evals/baseline-catalog.json +14 -0
- procesio_cli/skills/evals/baseline-routing-v2.json +38 -0
- procesio_cli/skills/evals/baseline.json +37 -0
- procesio_cli/skills/evals/behavioral.json +367 -0
- procesio_cli/skills/evals/field-boundary-development-v1.json +126 -0
- procesio_cli/skills/evals/field-closeout-correction-development-v1.json +23 -0
- procesio_cli/skills/evals/field-closeout-development-v1.json +89 -0
- procesio_cli/skills/evals/portfolio-pressure-training-v1.json +83 -0
- procesio_cli/skills/evals/routing.json +363 -0
- procesio_cli/skills/evals/validation-baseline.json +4 -0
- procesio_cli/skills/procesio-cli/SKILL.md +134 -0
- procesio_cli/skills/procesio-cli/evals/evals.json +111 -0
- procesio_cli/skills/procesio-cli/evals/workflows.json +16 -0
- procesio_cli/skills/procesio-cli/references/connector-lifecycle.md +47 -0
- procesio_cli/skills/procesio-cli/references/credentials-admin.md +113 -0
- procesio_cli/skills/procesio-cli/references/data-verification.md +71 -0
- procesio_cli/skills/procesio-cli/references/documents-files.md +44 -0
- procesio_cli/skills/procesio-cli/references/form-e2e.md +57 -0
- procesio_cli/skills/procesio-cli/references/operation-contract.md +138 -0
- procesio_cli/skills/procesio-cli/references/process-debugging.md +65 -0
- procesio_cli/skills/procesio-cli/references/process-lifecycle.md +88 -0
- procesio_cli/skills/procesio-cli/references/schedules-webhooks.md +58 -0
- procesio_cli/skills/procesio-cli/references/transport-environments.md +53 -0
- procesio_cli/skills/procesio-cli-maintainer/SKILL.md +84 -0
- procesio_cli/skills/procesio-cli-maintainer/evals/evals.json +116 -0
- procesio_cli/skills/procesio-cli-maintainer/references/change-contract.md +34 -0
- procesio_cli/skills/procesio-cli-maintainer/references/mcp-compatibility.md +13 -0
- procesio_cli/skills/procesio-cli-maintainer/references/skill-authoring.md +51 -0
- procesio_cli/skills/procesio-platform-advisor/SKILL.md +82 -0
- procesio_cli/skills/procesio-platform-advisor/evals/evals.json +116 -0
- procesio_cli/skills/procesio-platform-advisor/references/capability-map.md +22 -0
- procesio_cli/skills/procesio-platform-advisor/references/fit-framework.md +35 -0
- procesio_cli/skills/procesio-platform-advisor/references/freshness-policy.md +25 -0
- procesio_cli/skills/procesio-platform-advisor/references/sizing-method.md +70 -0
- procesio_cli/skills/procesio-platform-advisor/scripts/estimate_capacity.py +99 -0
- procesio_cli/skills/procesio-setup/SKILL.md +180 -0
- procesio_cli/skills/sql-server-optimizer/SKILL.md +86 -0
- procesio_cli/skills/sql-server-optimizer/evals/evals.json +116 -0
- procesio_cli/skills/sql-server-optimizer/references/db-context.md +44 -0
- procesio_cli/skills/sql-server-optimizer/references/generic-mode.md +32 -0
- procesio_cli/skills/sql-server-optimizer/references/procesio-mode.md +40 -0
- procesio_cli/skills/sql-server-optimizer/references/sql-rules.md +43 -0
- procesio_cli/skills/sql-server-optimizer/scripts/export-indexes.sql +178 -0
- procesio_cli/skills/sql-server-optimizer/scripts/export-procs-and-functions.sql +118 -0
- procesio_cli/skills/sql-server-optimizer/scripts/export-tables.sql +367 -0
- procesio_cli/skills/tests/__init__.py +0 -0
- procesio_cli/skills/tests/test_agent_skill_engineer.py +240 -0
- procesio_cli/skills/tests/test_auth_failure_stop.py +25 -0
- procesio_cli/skills/tests/test_capacity_estimator.py +85 -0
- procesio_cli/skills/tests/test_field_boundary_learning.py +100 -0
- procesio_cli/skills/tests/test_field_closeout_learning.py +123 -0
- procesio_cli/skills/tests/test_field_gate_standard.py +76 -0
- procesio_cli/skills/tests/test_operational_playbooks.py +51 -0
- procesio_cli/skills/tests/test_portfolio_pressure_training.py +35 -0
- procesio_cli/skills/tests/test_process_lifecycle_single_run.py +25 -0
- procesio_cli/skills/tests/test_skill_evaluator.py +67 -0
- procesio_cli/skills/tests/test_skill_optimizer.py +473 -0
- procesio_cli/skills/tests/test_skill_portfolio_review.py +70 -0
- procesio_cli/skills/tests/test_skill_release_binding.py +204 -0
- procesio_cli/skills/tests/test_skill_routing.py +74 -0
- procesio_cli/skills/tests/test_skill_scaffold_v2.py +116 -0
- procesio_cli/skills/tests/test_validate_skills.py +115 -0
- procesio_cli/tools/__init__.py +0 -0
- procesio_cli/tools/_lib/README.md +119 -0
- procesio_cli/tools/_lib/__init__.py +0 -0
- procesio_cli/tools/_lib/accounting.py +120 -0
- procesio_cli/tools/_lib/contacts.py +544 -0
- procesio_cli/tools/_lib/creds.py +83 -0
- procesio_cli/tools/_lib/creds_backends.py +578 -0
- procesio_cli/tools/_lib/dbprofiles.py +147 -0
- procesio_cli/tools/_lib/dbquery.py +286 -0
- procesio_cli/tools/_lib/dbschema.py +225 -0
- procesio_cli/tools/_lib/io.py +54 -0
- procesio_cli/tools/_lib/manifest.py +297 -0
- procesio_cli/tools/_lib/skill_release.py +127 -0
- procesio_cli/tools/_lib/skill_resources.py +118 -0
- procesio_cli/tools/_lib/userdata.py +228 -0
- procesio_cli/tools/_lib/webserialize/__init__.py +16 -0
- procesio_cli/tools/_lib/webserialize/admin.py +61 -0
- procesio_cli/tools/_lib/webserialize/client.py +264 -0
- procesio_cli/tools/_lib/webserialize/config.py +96 -0
- procesio_cli/tools/_lib/webserialize/errors.py +27 -0
- procesio_cli/tools/_lib/webserialize/framing.py +45 -0
- procesio_cli/tools/_lib/webserialize/registry.py +47 -0
- procesio_cli/tools/_lib/webserialize/runtime.py +61 -0
- procesio_cli/tools/_lib/webserialize/server.py +510 -0
- procesio_cli/tools/_lib/websession.py +194 -0
- procesio_cli/tools/connector-builder/CONNECTOR-BUILDER-API-NOTES.md +91 -0
- procesio_cli/tools/connector-builder/README.md +101 -0
- procesio_cli/tools/connector-builder/SKILL.md +248 -0
- procesio_cli/tools/connector-builder/__init__.py +7 -0
- procesio_cli/tools/connector-builder/actiondef.py +24 -0
- procesio_cli/tools/connector-builder/client.py +251 -0
- procesio_cli/tools/connector-builder/errors.py +44 -0
- procesio_cli/tools/connector-builder/gen_manifest.py +142 -0
- procesio_cli/tools/connector-builder/handlers/__init__.py +1 -0
- procesio_cli/tools/connector-builder/handlers/admin.py +182 -0
- procesio_cli/tools/connector-builder/handlers/auth.py +74 -0
- procesio_cli/tools/connector-builder/handlers/builds.py +396 -0
- procesio_cli/tools/connector-builder/handlers/common.py +104 -0
- procesio_cli/tools/connector-builder/handlers/files.py +111 -0
- procesio_cli/tools/connector-builder/handlers/raw.py +38 -0
- procesio_cli/tools/connector-builder/handlers/telemetry.py +39 -0
- procesio_cli/tools/connector-builder/main.py +94 -0
- procesio_cli/tools/connector-builder/tests/conftest.py +146 -0
- procesio_cli/tools/connector-builder/tests/test_cb_client.py +86 -0
- procesio_cli/tools/connector-builder/tests/test_cb_dispatch.py +105 -0
- procesio_cli/tools/connector-builder/tests/test_cb_manifest_sync.py +76 -0
- procesio_cli/tools/connector-builder/tests/test_cb_wait.py +123 -0
- procesio_cli/tools/connector-builder/tool.yaml +671 -0
- procesio_cli/tools/framework-map/.gitattributes +2 -0
- procesio_cli/tools/framework-map/README.md +98 -0
- procesio_cli/tools/framework-map/SKILL.md +30 -0
- procesio_cli/tools/framework-map/app.js +188 -0
- procesio_cli/tools/framework-map/fm_builder.py +476 -0
- procesio_cli/tools/framework-map/fm_catalog.py +19 -0
- procesio_cli/tools/framework-map/fm_ro_catalog.py +94 -0
- procesio_cli/tools/framework-map/fm_strings.py +101 -0
- procesio_cli/tools/framework-map/main.py +95 -0
- procesio_cli/tools/framework-map/styles.css +214 -0
- procesio_cli/tools/framework-map/tests/conftest.py +33 -0
- procesio_cli/tools/framework-map/tests/test_fm_build.py +126 -0
- procesio_cli/tools/framework-map/tests/test_fm_manifest_sync.py +63 -0
- procesio_cli/tools/framework-map/tests/test_fm_store_tree.py +75 -0
- procesio_cli/tools/framework-map/tool.yaml +61 -0
- procesio_cli/tools/mysql/MOVED-TO-CENTRAL.md +29 -0
- procesio_cli/tools/mysql/README.md +196 -0
- procesio_cli/tools/mysql/SKILL.md +37 -0
- procesio_cli/tools/mysql/__init__.py +0 -0
- procesio_cli/tools/mysql/connection.py +191 -0
- procesio_cli/tools/mysql/main.py +487 -0
- procesio_cli/tools/mysql/profiles.template.json +1 -0
- procesio_cli/tools/mysql/schema.py +434 -0
- procesio_cli/tools/mysql/tests/__init__.py +0 -0
- procesio_cli/tools/mysql/tests/conftest.py +21 -0
- procesio_cli/tools/mysql/tests/test_manifest_sync.py +68 -0
- procesio_cli/tools/mysql/tests/test_mysql.py +201 -0
- procesio_cli/tools/mysql/tests/test_mysql_schema.py +337 -0
- procesio_cli/tools/mysql/tool.yaml +112 -0
- procesio_cli/tools/procesio/DTO-SUBTOOLS-NOTE.md +360 -0
- procesio_cli/tools/procesio/FORM-DEV-GUIDE/00-INDEX.md +67 -0
- procesio_cli/tools/procesio/FORM-DEV-GUIDE/01-ANATOMY.md +209 -0
- procesio_cli/tools/procesio/FORM-DEV-GUIDE/02-CODE-INJECTION.md +309 -0
- procesio_cli/tools/procesio/FORM-DEV-GUIDE/03-DOM-CONTRACT.md +370 -0
- procesio_cli/tools/procesio/FORM-DEV-GUIDE/04-INTERACTION-RECIPES.md +600 -0
- procesio_cli/tools/procesio/FORM-DEV-GUIDE/05-STEPPER-AND-MOTION.md +426 -0
- procesio_cli/tools/procesio/FORM-DEV-GUIDE/06-PROCESS-INTEGRATION.md +347 -0
- procesio_cli/tools/procesio/FORM-DEV-GUIDE/07-DEPLOY-WORKFLOW.md +294 -0
- procesio_cli/tools/procesio/FORM-DEV-GUIDE/08-PITFALLS.md +569 -0
- procesio_cli/tools/procesio/FORM-DEV-GUIDE/09-NAVIGATION-AND-HOSTING.md +308 -0
- procesio_cli/tools/procesio/PHASE4-E2E-NOTES.md +594 -0
- procesio_cli/tools/procesio/PROCESIO-API-CORRECTIONS.md +295 -0
- procesio_cli/tools/procesio/PROCESIO-API-NOTES.md +6976 -0
- procesio_cli/tools/procesio/PROCESIO-AUTH-NOTES.md +226 -0
- procesio_cli/tools/procesio/PROCESIO-CARD-BUILD-NOTES.md +183 -0
- procesio_cli/tools/procesio/PROCESIO-CONNECTORS-NOTES.md +141 -0
- procesio_cli/tools/procesio/PROCESIO-CUSTOM-ACTION-NOTES.md +179 -0
- procesio_cli/tools/procesio/PROCESIO-DOCS-FIX-REPORT.md +123 -0
- procesio_cli/tools/procesio/PROCESIO-ENVIRONMENTS-NOTES.md +94 -0
- procesio_cli/tools/procesio/PROCESIO-FE-VALIDATION-NOTES.md +107 -0
- procesio_cli/tools/procesio/PROCESIO-FOREACH-NOTES.md +199 -0
- procesio_cli/tools/procesio/PROCESIO-FORM-API-HANG-NOTE.md +101 -0
- procesio_cli/tools/procesio/PROCESIO-FORM-SUBMISSION-NOTES.md +172 -0
- procesio_cli/tools/procesio/PROCESIO-HTML-TO-DOCX-NOTES.md +110 -0
- procesio_cli/tools/procesio/PROCESIO-INSTANCE-HISTORY-NOTES.md +242 -0
- procesio_cli/tools/procesio/PROCESIO-METERING-NOTES.md +201 -0
- procesio_cli/tools/procesio/PROCESIO-NODE-CODE-NOTES.md +279 -0
- procesio_cli/tools/procesio/PROCESIO-NODE-MODULE-WHITELIST.md +113 -0
- procesio_cli/tools/procesio/PROCESIO-PYTHON-ACTION-NOTES.md +165 -0
- procesio_cli/tools/procesio/PROCESIO-QUERY-STORE-NOTES.md +826 -0
- procesio_cli/tools/procesio/PROCESIO-RECONCILIATION-PATTERNS.md +104 -0
- procesio_cli/tools/procesio/PROCESIO-RESOURCE-MODEL-NOTES.md +1100 -0
- procesio_cli/tools/procesio/PROCESIO-SEND-EMAIL-CRED-OPTIONALITY.md +45 -0
- procesio_cli/tools/procesio/PROCESIO-SEND-EMAIL-NOTES.md +252 -0
- procesio_cli/tools/procesio/PROCESIO-SQL-ACTIONS-NOTES.md +284 -0
- procesio_cli/tools/procesio/PROCESIO-USAGE-GUIDE.md +219 -0
- procesio_cli/tools/procesio/README.md +341 -0
- procesio_cli/tools/procesio/SCHEDULE-INPUT-SECURITY-NOTES.md +63 -0
- procesio_cli/tools/procesio/SKILL.md +694 -0
- procesio_cli/tools/procesio/__init__.py +1 -0
- procesio_cli/tools/procesio/actiondef.py +27 -0
- procesio_cli/tools/procesio/assets/html2docx/html2docx.js +2155 -0
- procesio_cli/tools/procesio/auth.py +354 -0
- procesio_cli/tools/procesio/autogen.py +121 -0
- procesio_cli/tools/procesio/client.py +355 -0
- procesio_cli/tools/procesio/config.py +96 -0
- procesio_cli/tools/procesio/data/endpoints.json +2901 -0
- procesio_cli/tools/procesio/docs_info/API-DOCUMENTATION/01-authentication.md +180 -0
- procesio_cli/tools/procesio/docs_info/API-DOCUMENTATION/02-conventions.md +116 -0
- procesio_cli/tools/procesio/docs_info/API-DOCUMENTATION/ANONYMOUS-SURFACE.md +51 -0
- procesio_cli/tools/procesio/docs_info/API-DOCUMENTATION/README.md +104 -0
- procesio_cli/tools/procesio/docs_info/API-DOCUMENTATION/SYMBOL-INDEX.md +444 -0
- procesio_cli/tools/procesio/docs_info/API-DOCUMENTATION/endpoints/03-auth-users-workspaces.md +731 -0
- procesio_cli/tools/procesio/docs_info/API-DOCUMENTATION/endpoints/04-processes.md +913 -0
- procesio_cli/tools/procesio/docs_info/API-DOCUMENTATION/endpoints/05-actions.md +605 -0
- procesio_cli/tools/procesio/docs_info/API-DOCUMENTATION/endpoints/06-files.md +237 -0
- procesio_cli/tools/procesio/docs_info/API-DOCUMENTATION/endpoints/07-forms-documents.md +985 -0
- procesio_cli/tools/procesio/docs_info/API-DOCUMENTATION/endpoints/08-credentials.md +532 -0
- procesio_cli/tools/procesio/docs_info/API-DOCUMENTATION/endpoints/09-datastore-datatypes.md +830 -0
- procesio_cli/tools/procesio/docs_info/API-DOCUMENTATION/endpoints/10-custom-urls.md +319 -0
- procesio_cli/tools/procesio/docs_info/API-DOCUMENTATION/endpoints/11-subscriptions-resources-analytics.md +455 -0
- procesio_cli/tools/procesio/docs_info/API-DOCUMENTATION/endpoints/12-webhooks-notifications-misc.md +519 -0
- procesio_cli/tools/procesio/docs_info/API-DOCUMENTATION/endpoints/13-realtime-signalr.md +153 -0
- procesio_cli/tools/procesio/docs_info/API-DOCUMENTATION/endpoints/99-internal-and-other-services.md +52 -0
- procesio_cli/tools/procesio/docs_info/FormBuilder mock.ts +5725 -0
- procesio_cli/tools/procesio/docs_info/Procesio Platform Actions.json +30219 -0
- procesio_cli/tools/procesio/docs_info/form-config-enums.ts +92 -0
- procesio_cli/tools/procesio/docs_info/form-theme.ts +1603 -0
- procesio_cli/tools/procesio/docs_info/process-validation-reference-1.md +2739 -0
- procesio_cli/tools/procesio/dto/__init__.py +13 -0
- procesio_cli/tools/procesio/dto/credential/builder.py +179 -0
- procesio_cli/tools/procesio/dto/credential/config.schema.json +19 -0
- procesio_cli/tools/procesio/dto/credential/description.md +193 -0
- procesio_cli/tools/procesio/dto/credential/fixtures/rest.config.json +11 -0
- procesio_cli/tools/procesio/dto/credential/fixtures/rest.dto.json +28 -0
- procesio_cli/tools/procesio/dto/credential/fixtures/rest.template.json +44 -0
- procesio_cli/tools/procesio/dto/credential/template.dto.json +16 -0
- procesio_cli/tools/procesio/dto/data/_refresh.py +147 -0
- procesio_cli/tools/procesio/dto/data/action_catalog.json +30825 -0
- procesio_cli/tools/procesio/dto/data/action_families.json +55 -0
- procesio_cli/tools/procesio/dto/data/platform_types.json +182 -0
- procesio_cli/tools/procesio/dto/datatype/builder.py +223 -0
- procesio_cli/tools/procesio/dto/datatype/config.schema.json +47 -0
- procesio_cli/tools/procesio/dto/datatype/description.md +85 -0
- procesio_cli/tools/procesio/dto/datatype/fixtures/customer.config.json +41 -0
- procesio_cli/tools/procesio/dto/datatype/fixtures/customer.dto.json +164 -0
- procesio_cli/tools/procesio/dto/datatype/template.dto.json +37 -0
- procesio_cli/tools/procesio/dto/document/builder.py +193 -0
- procesio_cli/tools/procesio/dto/document/config.schema.json +33 -0
- procesio_cli/tools/procesio/dto/document/description.md +124 -0
- procesio_cli/tools/procesio/dto/document/fixtures/invoice.config.json +16 -0
- procesio_cli/tools/procesio/dto/document/fixtures/invoice.dto.json +32 -0
- procesio_cli/tools/procesio/dto/document/template.dto.json +14 -0
- procesio_cli/tools/procesio/dto/form/FORM-STYLING-NOTES.md +142 -0
- procesio_cli/tools/procesio/dto/form/GOLDEN-DRIFT-NOTES.md +72 -0
- procesio_cli/tools/procesio/dto/form/RUN-PROCESS-RESULT-NOTES.md +80 -0
- procesio_cli/tools/procesio/dto/form/addelement.py +277 -0
- procesio_cli/tools/procesio/dto/form/builder.py +1009 -0
- procesio_cli/tools/procesio/dto/form/capture_goldens.py +106 -0
- procesio_cli/tools/procesio/dto/form/code_cipher.py +67 -0
- procesio_cli/tools/procesio/dto/form/config.schema.json +76 -0
- procesio_cli/tools/procesio/dto/form/data_shell.json +1 -0
- procesio_cli/tools/procesio/dto/form/description.md +346 -0
- procesio_cli/tools/procesio/dto/form/elements/approval.json +259 -0
- procesio_cli/tools/procesio/dto/form/elements/assignee.json +137 -0
- procesio_cli/tools/procesio/dto/form/elements/button.json +125 -0
- procesio_cli/tools/procesio/dto/form/elements/chart.json +341 -0
- procesio_cli/tools/procesio/dto/form/elements/chat.json +199 -0
- procesio_cli/tools/procesio/dto/form/elements/checkbox.json +153 -0
- procesio_cli/tools/procesio/dto/form/elements/column.json +77 -0
- procesio_cli/tools/procesio/dto/form/elements/columns.json +78 -0
- procesio_cli/tools/procesio/dto/form/elements/datetime-input.json +304 -0
- procesio_cli/tools/procesio/dto/form/elements/divider.json +54 -0
- procesio_cli/tools/procesio/dto/form/elements/dropdown.json +130 -0
- procesio_cli/tools/procesio/dto/form/elements/dynamic-table-row.json +253 -0
- procesio_cli/tools/procesio/dto/form/elements/file-upload.json +196 -0
- procesio_cli/tools/procesio/dto/form/elements/file-viewer.json +169 -0
- procesio_cli/tools/procesio/dto/form/elements/heading.json +79 -0
- procesio_cli/tools/procesio/dto/form/elements/icon.json +107 -0
- procesio_cli/tools/procesio/dto/form/elements/image.json +174 -0
- procesio_cli/tools/procesio/dto/form/elements/input.json +206 -0
- procesio_cli/tools/procesio/dto/form/elements/list.json +202 -0
- procesio_cli/tools/procesio/dto/form/elements/number-input.json +202 -0
- procesio_cli/tools/procesio/dto/form/elements/paragraph.json +79 -0
- procesio_cli/tools/procesio/dto/form/elements/radiobox.json +174 -0
- procesio_cli/tools/procesio/dto/form/elements/section.json +114 -0
- procesio_cli/tools/procesio/dto/form/elements/select.json +217 -0
- procesio_cli/tools/procesio/dto/form/elements/side-panel.json +146 -0
- procesio_cli/tools/procesio/dto/form/elements/signature-pad.json +141 -0
- procesio_cli/tools/procesio/dto/form/elements/static-table-row.json +84 -0
- procesio_cli/tools/procesio/dto/form/elements/step.json +105 -0
- procesio_cli/tools/procesio/dto/form/elements/stepper.json +126 -0
- procesio_cli/tools/procesio/dto/form/elements/tab.json +77 -0
- procesio_cli/tools/procesio/dto/form/elements/table.json +279 -0
- procesio_cli/tools/procesio/dto/form/elements/tabs.json +114 -0
- procesio_cli/tools/procesio/dto/form/elements/textarea.json +213 -0
- procesio_cli/tools/procesio/dto/form/enum_map.json +68 -0
- procesio_cli/tools/procesio/dto/form/fieldpath.py +284 -0
- procesio_cli/tools/procesio/dto/form/fixtures/reg.config.json +32 -0
- procesio_cli/tools/procesio/dto/form/fixtures/reg.elements.json +638 -0
- procesio_cli/tools/procesio/dto/form/sync_from_mock.py +386 -0
- procesio_cli/tools/procesio/dto/framework.py +125 -0
- procesio_cli/tools/procesio/dto/process/builder.py +1991 -0
- procesio_cli/tools/procesio/dto/process/config.schema.json +159 -0
- procesio_cli/tools/procesio/dto/process/description.md +218 -0
- procesio_cli/tools/procesio/dto/process/fixtures/greet.config.json +32 -0
- procesio_cli/tools/procesio/dto/process/fixtures/greet.dto.json +317 -0
- procesio_cli/tools/procesio/dto/process/naming.py +305 -0
- procesio_cli/tools/procesio/dto/process/normalize.py +74 -0
- procesio_cli/tools/procesio/dto/process/template.dto.json +32 -0
- procesio_cli/tools/procesio/dto/refdata.py +87 -0
- procesio_cli/tools/procesio/dto/registry.py +27 -0
- procesio_cli/tools/procesio/dto/webhook/builder.py +142 -0
- procesio_cli/tools/procesio/dto/webhook/config.schema.json +25 -0
- procesio_cli/tools/procesio/dto/webhook/description.md +92 -0
- procesio_cli/tools/procesio/dto/webhook/fixtures/order.config.json +10 -0
- procesio_cli/tools/procesio/dto/webhook/fixtures/order.dto.json +25 -0
- procesio_cli/tools/procesio/dto/webhook/template.dto.json +14 -0
- procesio_cli/tools/procesio/environments.py +264 -0
- procesio_cli/tools/procesio/errors.py +166 -0
- procesio_cli/tools/procesio/flowmodel/README.md +37 -0
- procesio_cli/tools/procesio/flowmodel/__init__.py +14 -0
- procesio_cli/tools/procesio/flowmodel/digest.py +223 -0
- procesio_cli/tools/procesio/flowmodel/families.py +34 -0
- procesio_cli/tools/procesio/flowmodel/fevalidation.py +1098 -0
- procesio_cli/tools/procesio/flowmodel/formdigest.py +232 -0
- procesio_cli/tools/procesio/flowmodel/inspect.py +78 -0
- procesio_cli/tools/procesio/flowmodel/model.py +82 -0
- procesio_cli/tools/procesio/flowmodel/nodeparam.py +871 -0
- procesio_cli/tools/procesio/flowmodel/reader.py +191 -0
- procesio_cli/tools/procesio/flowmodel/sqlparam.py +410 -0
- procesio_cli/tools/procesio/form_code_keys.py +50 -0
- procesio_cli/tools/procesio/formlint.py +292 -0
- procesio_cli/tools/procesio/gen_manifest.py +118 -0
- procesio_cli/tools/procesio/handlers/__init__.py +1 -0
- procesio_cli/tools/procesio/handlers/auth_actions.py +103 -0
- procesio_cli/tools/procesio/handlers/catalog.py +147 -0
- procesio_cli/tools/procesio/handlers/common.py +90 -0
- procesio_cli/tools/procesio/handlers/customaction_ops.py +146 -0
- procesio_cli/tools/procesio/handlers/datastore_ops.py +482 -0
- procesio_cli/tools/procesio/handlers/datatype_ops.py +275 -0
- procesio_cli/tools/procesio/handlers/dto_actions.py +258 -0
- procesio_cli/tools/procesio/handlers/environment_admin.py +146 -0
- procesio_cli/tools/procesio/handlers/fevalidate.py +236 -0
- procesio_cli/tools/procesio/handlers/files.py +141 -0
- procesio_cli/tools/procesio/handlers/flowgraph.py +229 -0
- procesio_cli/tools/procesio/handlers/flowlint.py +269 -0
- procesio_cli/tools/procesio/handlers/form_chains.py +336 -0
- procesio_cli/tools/procesio/handlers/form_code.py +277 -0
- procesio_cli/tools/procesio/handlers/form_element.py +199 -0
- procesio_cli/tools/procesio/handlers/form_events.py +441 -0
- procesio_cli/tools/procesio/handlers/form_update.py +270 -0
- procesio_cli/tools/procesio/handlers/formprocess.py +211 -0
- procesio_cli/tools/procesio/handlers/generic.py +135 -0
- procesio_cli/tools/procesio/handlers/layout.py +137 -0
- procesio_cli/tools/procesio/handlers/nodeparams.py +1018 -0
- procesio_cli/tools/procesio/handlers/process_layout.py +189 -0
- procesio_cli/tools/procesio/handlers/process_naming.py +213 -0
- procesio_cli/tools/procesio/handlers/processes.py +416 -0
- procesio_cli/tools/procesio/handlers/profile_admin.py +184 -0
- procesio_cli/tools/procesio/handlers/resource_ops.py +447 -0
- procesio_cli/tools/procesio/handlers/schedules.py +320 -0
- procesio_cli/tools/procesio/handlers/sqlactions.py +232 -0
- procesio_cli/tools/procesio/handlers/transport.py +463 -0
- procesio_cli/tools/procesio/handlers/usageguide.py +222 -0
- procesio_cli/tools/procesio/layout/README.md +196 -0
- procesio_cli/tools/procesio/layout/__init__.py +11 -0
- procesio_cli/tools/procesio/layout/adapter.py +736 -0
- procesio_cli/tools/procesio/layout/cycles.py +186 -0
- procesio_cli/tools/procesio/layout/dispatch.py +39 -0
- procesio_cli/tools/procesio/layout/elk/elk_runner.mjs +50 -0
- procesio_cli/tools/procesio/layout/elk/package-lock.json +21 -0
- procesio_cli/tools/procesio/layout/elk/package.json +11 -0
- procesio_cli/tools/procesio/layout/elk_engine.py +568 -0
- procesio_cli/tools/procesio/layout/engine.py +1311 -0
- procesio_cli/tools/procesio/layout/report.py +187 -0
- procesio_cli/tools/procesio/main.py +179 -0
- procesio_cli/tools/procesio/profiles.py +193 -0
- procesio_cli/tools/procesio/reliability.py +193 -0
- procesio_cli/tools/procesio/sqlformat.py +167 -0
- procesio_cli/tools/procesio/swagger.py +51 -0
- procesio_cli/tools/procesio/tests/__init__.py +0 -0
- procesio_cli/tools/procesio/tests/conftest.py +129 -0
- procesio_cli/tools/procesio/tests/test_auth.py +200 -0
- procesio_cli/tools/procesio/tests/test_autogen.py +78 -0
- procesio_cli/tools/procesio/tests/test_builder_attrpath_sqlbind.py +180 -0
- procesio_cli/tools/procesio/tests/test_builder_custom_action_catalog.py +72 -0
- procesio_cli/tools/procesio/tests/test_client.py +114 -0
- procesio_cli/tools/procesio/tests/test_client_reliability.py +139 -0
- procesio_cli/tools/procesio/tests/test_customaction.py +103 -0
- procesio_cli/tools/procesio/tests/test_customaction_test.py +80 -0
- procesio_cli/tools/procesio/tests/test_cycles.py +69 -0
- procesio_cli/tools/procesio/tests/test_datastore.py +378 -0
- procesio_cli/tools/procesio/tests/test_datastore_node.py +94 -0
- procesio_cli/tools/procesio/tests/test_dispatch.py +170 -0
- procesio_cli/tools/procesio/tests/test_document_page_size.py +19 -0
- procesio_cli/tools/procesio/tests/test_dto.py +734 -0
- procesio_cli/tools/procesio/tests/test_edit_dryrun_preview.py +96 -0
- procesio_cli/tools/procesio/tests/test_elk_layout.py +221 -0
- procesio_cli/tools/procesio/tests/test_environments.py +214 -0
- procesio_cli/tools/procesio/tests/test_fevalidate_gate.py +104 -0
- procesio_cli/tools/procesio/tests/test_fevalidation.py +317 -0
- procesio_cli/tools/procesio/tests/test_fieldpath_variables.py +87 -0
- procesio_cli/tools/procesio/tests/test_files.py +72 -0
- procesio_cli/tools/procesio/tests/test_flow_digest.py +202 -0
- procesio_cli/tools/procesio/tests/test_flowlint.py +114 -0
- procesio_cli/tools/procesio/tests/test_flowmodel.py +158 -0
- procesio_cli/tools/procesio/tests/test_form_add_element.py +256 -0
- procesio_cli/tools/procesio/tests/test_form_approval_gaps.py +319 -0
- procesio_cli/tools/procesio/tests/test_form_auto_names.py +60 -0
- procesio_cli/tools/procesio/tests/test_form_chains.py +217 -0
- procesio_cli/tools/procesio/tests/test_form_code_actions.py +188 -0
- procesio_cli/tools/procesio/tests/test_form_code_keys.py +92 -0
- procesio_cli/tools/procesio/tests/test_form_code_style.py +178 -0
- procesio_cli/tools/procesio/tests/test_form_delete_element.py +99 -0
- procesio_cli/tools/procesio/tests/test_form_element_config.py +141 -0
- procesio_cli/tools/procesio/tests/test_form_event_maps.py +135 -0
- procesio_cli/tools/procesio/tests/test_form_event_ops.py +376 -0
- procesio_cli/tools/procesio/tests/test_form_event_replace.py +86 -0
- procesio_cli/tools/procesio/tests/test_form_events.py +92 -0
- procesio_cli/tools/procesio/tests/test_form_parity.py +171 -0
- procesio_cli/tools/procesio/tests/test_form_select_source.py +74 -0
- procesio_cli/tools/procesio/tests/test_form_sync.py +35 -0
- procesio_cli/tools/procesio/tests/test_form_update.py +133 -0
- procesio_cli/tools/procesio/tests/test_formlint.py +155 -0
- procesio_cli/tools/procesio/tests/test_formlint_css_scope.py +38 -0
- procesio_cli/tools/procesio/tests/test_formlint_field_names.py +83 -0
- procesio_cli/tools/procesio/tests/test_guards.py +110 -0
- procesio_cli/tools/procesio/tests/test_hidden_setting_types.py +39 -0
- procesio_cli/tools/procesio/tests/test_html2docx_asset.py +132 -0
- procesio_cli/tools/procesio/tests/test_key_handle_terminology.py +45 -0
- procesio_cli/tools/procesio/tests/test_layout.py +574 -0
- procesio_cli/tools/procesio/tests/test_layout_report.py +88 -0
- procesio_cli/tools/procesio/tests/test_manifest_sync.py +68 -0
- procesio_cli/tools/procesio/tests/test_nodedelete.py +151 -0
- procesio_cli/tools/procesio/tests/test_nodeparam.py +826 -0
- procesio_cli/tools/procesio/tests/test_normalize.py +70 -0
- procesio_cli/tools/procesio/tests/test_payload_docs.py +86 -0
- procesio_cli/tools/procesio/tests/test_process_action_naming.py +170 -0
- procesio_cli/tools/procesio/tests/test_process_call_api_seed.py +46 -0
- procesio_cli/tools/procesio/tests/test_process_ext.py +373 -0
- procesio_cli/tools/procesio/tests/test_process_invariants.py +183 -0
- procesio_cli/tools/procesio/tests/test_process_layout.py +117 -0
- procesio_cli/tools/procesio/tests/test_process_naming.py +188 -0
- procesio_cli/tools/procesio/tests/test_process_query_store.py +172 -0
- procesio_cli/tools/procesio/tests/test_processinfo_variable.py +56 -0
- procesio_cli/tools/procesio/tests/test_profiles.py +127 -0
- procesio_cli/tools/procesio/tests/test_put_projects.py +41 -0
- procesio_cli/tools/procesio/tests/test_reliability.py +107 -0
- procesio_cli/tools/procesio/tests/test_removal_gate.py +95 -0
- procesio_cli/tools/procesio/tests/test_resource_ops.py +173 -0
- procesio_cli/tools/procesio/tests/test_save_validity.py +207 -0
- procesio_cli/tools/procesio/tests/test_schedule_cron_shape.py +111 -0
- procesio_cli/tools/procesio/tests/test_schedules.py +309 -0
- procesio_cli/tools/procesio/tests/test_sqlconvert.py +234 -0
- procesio_cli/tools/procesio/tests/test_sqlformat.py +83 -0
- procesio_cli/tools/procesio/tests/test_sqlparam.py +187 -0
- procesio_cli/tools/procesio/tests/test_superseded_actions.py +54 -0
- procesio_cli/tools/procesio/tests/test_surgical_concurrency.py +156 -0
- procesio_cli/tools/procesio/tests/test_tier4.py +123 -0
- procesio_cli/tools/procesio/tests/test_transport.py +147 -0
- procesio_cli/tools/procesio/tests/test_transport_data_stores.py +168 -0
- procesio_cli/tools/procesio/tests/test_transport_mapper_repair.py +150 -0
- procesio_cli/tools/procesio/tests/test_transport_webhook_strip.py +253 -0
- procesio_cli/tools/procesio/tests/test_usage_guide.py +96 -0
- procesio_cli/tools/procesio/tool.yaml +12486 -0
- procesio_cli/tools/sqlserver/MOVED-TO-CENTRAL.md +29 -0
- procesio_cli/tools/sqlserver/README.md +192 -0
- procesio_cli/tools/sqlserver/SKILL.md +37 -0
- procesio_cli/tools/sqlserver/SQLSERVER-SCHEMA-NOTES.md +284 -0
- procesio_cli/tools/sqlserver/__init__.py +0 -0
- procesio_cli/tools/sqlserver/connection.py +242 -0
- procesio_cli/tools/sqlserver/main.py +521 -0
- procesio_cli/tools/sqlserver/profiles.template.json +1 -0
- procesio_cli/tools/sqlserver/schema.py +600 -0
- procesio_cli/tools/sqlserver/tests/__init__.py +0 -0
- procesio_cli/tools/sqlserver/tests/conftest.py +21 -0
- procesio_cli/tools/sqlserver/tests/test_connection.py +75 -0
- procesio_cli/tools/sqlserver/tests/test_dbprofiles.py +92 -0
- procesio_cli/tools/sqlserver/tests/test_dbquery.py +220 -0
- procesio_cli/tools/sqlserver/tests/test_manifest_sync.py +68 -0
- procesio_cli/tools/sqlserver/tests/test_sqlserver.py +326 -0
- procesio_cli/tools/sqlserver/tests/test_sqlserver_schema.py +488 -0
- procesio_cli/tools/sqlserver/tool.yaml +123 -0
- procesio_cli/tools/web/README.md +381 -0
- procesio_cli/tools/web/SKILL.md +37 -0
- procesio_cli/tools/web/WEB-AUTOMATION-NOTES.md +277 -0
- procesio_cli/tools/web/__init__.py +21 -0
- procesio_cli/tools/web/actiondef.py +24 -0
- procesio_cli/tools/web/api.py +444 -0
- procesio_cli/tools/web/brokered.py +107 -0
- procesio_cli/tools/web/driver.py +839 -0
- procesio_cli/tools/web/drivercontract.py +44 -0
- procesio_cli/tools/web/errors.py +54 -0
- procesio_cli/tools/web/handlers/__init__.py +1 -0
- procesio_cli/tools/web/handlers/archive.py +367 -0
- procesio_cli/tools/web/handlers/browse.py +182 -0
- procesio_cli/tools/web/handlers/contacts.py +74 -0
- procesio_cli/tools/web/handlers/sessmgmt.py +120 -0
- procesio_cli/tools/web/main.py +128 -0
- procesio_cli/tools/web/sessions.py +253 -0
- procesio_cli/tools/web/steps.py +162 -0
- procesio_cli/tools/web/tests/__init__.py +0 -0
- procesio_cli/tools/web/tests/conftest.py +197 -0
- procesio_cli/tools/web/tests/test_api.py +330 -0
- procesio_cli/tools/web/tests/test_archive.py +190 -0
- procesio_cli/tools/web/tests/test_brokered.py +138 -0
- procesio_cli/tools/web/tests/test_dispatch.py +132 -0
- procesio_cli/tools/web/tests/test_errors.py +60 -0
- procesio_cli/tools/web/tests/test_manifest_sync.py +76 -0
- procesio_cli/tools/web/tests/test_page_contacts.py +68 -0
- procesio_cli/tools/web/tests/test_sessions.py +145 -0
- procesio_cli/tools/web/tests/test_steps.py +210 -0
- procesio_cli/tools/web/tool.yaml +184 -0
- procesio_cli/tools/xlsx/README.md +34 -0
- procesio_cli/tools/xlsx/SKILL.md +28 -0
- procesio_cli/tools/xlsx/__init__.py +0 -0
- procesio_cli/tools/xlsx/main.py +129 -0
- procesio_cli/tools/xlsx/reader.py +91 -0
- procesio_cli/tools/xlsx/tests/__init__.py +0 -0
- procesio_cli/tools/xlsx/tests/conftest.py +39 -0
- procesio_cli/tools/xlsx/tests/test_xlsx.py +103 -0
- procesio_cli/tools/xlsx/tool.yaml +30 -0
- procesio_cli/webplatform/aat_mcp/AAT-MCP-NOTES.md +244 -0
- procesio_cli/webplatform/aat_mcp/README.md +78 -0
- procesio_cli/webplatform/aat_mcp/bridge.py +705 -0
- procesio_cli/webplatform/aat_mcp/chat_server.py +194 -0
- procesio_cli/webplatform/aat_mcp/chat_surface.snapshot.json +668 -0
- procesio_cli/webplatform/aat_mcp/chat_surface.yaml +372 -0
- procesio_cli/webplatform/aat_mcp/gate.py +68 -0
- procesio_cli/webplatform/aat_mcp/http_server.py +139 -0
- procesio_cli/webplatform/aat_mcp/protocol.py +175 -0
- procesio_cli/webplatform/aat_mcp/server.py +306 -0
- procesio_cli/webplatform/aat_mcp/tests/conftest.py +8 -0
- procesio_cli/webplatform/aat_mcp/tests/test_aat_mcp.py +255 -0
- procesio_cli/webplatform/aat_mcp/tests/test_chat_surface.py +247 -0
- procesio_cli/webplatform/aat_mcp/tests/test_discovery.py +489 -0
- procesio_cli/webplatform/aat_mcp/tests/test_multiuser.py +86 -0
- procesio_cli/webplatform/aat_mcp/tests/test_progressive_discovery.py +89 -0
- procesio_cli/webplatform/aat_mcp/tests/test_protocol.py +180 -0
- procesio_cli/webplatform/aat_mcp/tests/test_skill_discovery.py +23 -0
- procesio_cli-0.1.1.dist-info/METADATA +467 -0
- procesio_cli-0.1.1.dist-info/RECORD +647 -0
- procesio_cli-0.1.1.dist-info/WHEEL +4 -0
- procesio_cli-0.1.1.dist-info/entry_points.txt +7 -0
- procesio_cli-0.1.1.dist-info/licenses/LICENSE +201 -0
- procesio_cli-0.1.1.dist-info/licenses/NOTICE +5 -0
|
@@ -0,0 +1,584 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Scan tracked files for live-credential formats.
|
|
3
|
+
|
|
4
|
+
Backs Hard rule 1 ("No secrets in files. Ever.") with a mechanical check.
|
|
5
|
+
Runs as a CLI (pre-commit hook) and as an importable module (pytest guard).
|
|
6
|
+
|
|
7
|
+
Two properties matter more than the pattern list:
|
|
8
|
+
|
|
9
|
+
1. **Windowed reads.** A single-line 30 MB JSON export is normal here
|
|
10
|
+
(a .procesio export is one enormous line). A scanner that reads by line,
|
|
11
|
+
or that skips lines over some length, silently reports "clean" on exactly
|
|
12
|
+
the files most likely to carry a secret. This reads fixed-size chunks with
|
|
13
|
+
an overlap wider than the longest credential we match, so a token straddling
|
|
14
|
+
a chunk boundary is still found.
|
|
15
|
+
|
|
16
|
+
2. **Shape classification before reporting.** Most `Bearer <x>` occurrences in
|
|
17
|
+
a workflow export are GUIDs - variable references, not secrets. Classifying
|
|
18
|
+
by shape (guid / placeholder / jwt / opaque-high-entropy) is what keeps the
|
|
19
|
+
signal usable; without it the true positives drown.
|
|
20
|
+
|
|
21
|
+
Never emits a credential value. A finding is identified by sha256 prefix,
|
|
22
|
+
length and Shannon entropy, which is enough to match it against a vault entry
|
|
23
|
+
or to confirm a rotation without ever moving the secret itself.
|
|
24
|
+
"""
|
|
25
|
+
|
|
26
|
+
from __future__ import annotations
|
|
27
|
+
|
|
28
|
+
import argparse
|
|
29
|
+
import base64
|
|
30
|
+
import binascii
|
|
31
|
+
import hashlib
|
|
32
|
+
import json
|
|
33
|
+
import math
|
|
34
|
+
import os
|
|
35
|
+
import re
|
|
36
|
+
import subprocess
|
|
37
|
+
import sys
|
|
38
|
+
from collections import Counter
|
|
39
|
+
from dataclasses import dataclass, asdict
|
|
40
|
+
from pathlib import Path
|
|
41
|
+
from xml.etree import ElementTree
|
|
42
|
+
|
|
43
|
+
REPO_ROOT = Path(__file__).resolve().parent.parent
|
|
44
|
+
|
|
45
|
+
# Read 4 MB at a time, overlapping by 64 KB. The overlap must exceed the
|
|
46
|
+
# longest single token we can match (a long JWT); 64 KB is far above that.
|
|
47
|
+
CHUNK_BYTES = 4 * 1024 * 1024
|
|
48
|
+
OVERLAP_BYTES = 64 * 1024
|
|
49
|
+
|
|
50
|
+
# Entropy floor for calling an opaque string a credential, in bits/char.
|
|
51
|
+
# Hex-only tokens sit near 4.0, base64url near 5.5; English prose and
|
|
52
|
+
# dotted identifiers sit well below 3.2.
|
|
53
|
+
MIN_ENTROPY = 3.2
|
|
54
|
+
MIN_OPAQUE_LEN = 20
|
|
55
|
+
|
|
56
|
+
GUID_RE = re.compile(
|
|
57
|
+
r"\A[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-"
|
|
58
|
+
r"[0-9a-fA-F]{4}-[0-9a-fA-F]{12}\Z"
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
# Substrings that mark a value as a documentation placeholder rather than a
|
|
62
|
+
# live credential. Compared case-insensitively.
|
|
63
|
+
PLACEHOLDER_MARKERS = (
|
|
64
|
+
"xxxx", "your", "example", "placeholder", "changeme", "redacted",
|
|
65
|
+
"sample", "dummy", "insert", "replace", "<", ">", "{{", "}}", "...",
|
|
66
|
+
"abc123", "todo", "notarealkey", "scrubbed",
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
# Each rule: (name, compiled pattern, needs_entropy_check)
|
|
70
|
+
# Patterns are byte patterns - we scan bytes so we never have to guess an
|
|
71
|
+
# encoding on a 30 MB file.
|
|
72
|
+
RULES: list[tuple[str, re.Pattern[bytes], bool]] = [
|
|
73
|
+
("google-api-key", re.compile(rb"AIza[0-9A-Za-z_\-]{35}"), False),
|
|
74
|
+
("openai-key", re.compile(rb"\bsk-(?:proj-|ant-)?[A-Za-z0-9_\-]{20,}"), True),
|
|
75
|
+
("github-pat", re.compile(rb"\b(?:ghp|gho|ghu|ghs|ghr)_[A-Za-z0-9]{36,}"), False),
|
|
76
|
+
("github-fine-grained-pat", re.compile(rb"\bgithub_pat_[A-Za-z0-9_]{22,}"), False),
|
|
77
|
+
("slack-token", re.compile(rb"\bxox[abposr]-[A-Za-z0-9\-]{10,}"), False),
|
|
78
|
+
("aws-access-key-id", re.compile(rb"\bAKIA[0-9A-Z]{16}\b"), False),
|
|
79
|
+
("sendgrid-key", re.compile(rb"\bSG\.[A-Za-z0-9_\-]{22}\.[A-Za-z0-9_\-]{43}"), False),
|
|
80
|
+
(
|
|
81
|
+
"jwt",
|
|
82
|
+
re.compile(rb"\beyJ[A-Za-z0-9_\-]{8,}\.eyJ[A-Za-z0-9_\-]{8,}\.[A-Za-z0-9_\-]*"),
|
|
83
|
+
False,
|
|
84
|
+
),
|
|
85
|
+
(
|
|
86
|
+
"private-key-pem",
|
|
87
|
+
re.compile(rb"-----BEGIN (?:RSA |EC |DSA |OPENSSH |PGP )?PRIVATE KEY-----"),
|
|
88
|
+
False,
|
|
89
|
+
),
|
|
90
|
+
("twilio-account-sid", re.compile(rb"\bAC[0-9a-f]{32}\b"), False),
|
|
91
|
+
("twilio-api-key", re.compile(rb"\bSK[0-9a-f]{32}\b"), False),
|
|
92
|
+
("stripe-key", re.compile(rb"\b[rs]k_(?:live|test)_[A-Za-z0-9]{20,}"), False),
|
|
93
|
+
# Authorization headers. These fire constantly on GUID variable
|
|
94
|
+
# references, so the shape classifier below does the real work.
|
|
95
|
+
(
|
|
96
|
+
"http-authorization",
|
|
97
|
+
re.compile(rb"(?:Bearer|Basic)\s+([A-Za-z0-9_\-\.=+/]{20,})"),
|
|
98
|
+
True,
|
|
99
|
+
),
|
|
100
|
+
]
|
|
101
|
+
|
|
102
|
+
# Rules whose match is an identifier rather than a usable secret on its own.
|
|
103
|
+
# Still reported, at lower severity, because they name the account to rotate.
|
|
104
|
+
IDENTIFIER_ONLY = {"twilio-account-sid", "aws-access-key-id"}
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
# A run of base64 / base64url characters long enough to wrap a credential.
|
|
108
|
+
# Kept well above incidental identifiers (a GUID is 32 hex + dashes) so we do
|
|
109
|
+
# not try to decode every high-entropy token in a workflow export.
|
|
110
|
+
MIN_B64_RUN = 40
|
|
111
|
+
_B64_RUN = re.compile(rb"[A-Za-z0-9+/_\-]{%d,}={0,2}" % MIN_B64_RUN)
|
|
112
|
+
|
|
113
|
+
# How many base64 layers to peel. A Kubernetes dockerconfigjson Secret buries
|
|
114
|
+
# the token two layers down: the `.dockerconfigjson` value is base64 of a JSON
|
|
115
|
+
# doc whose `auth` field is itself base64 of `user:token`. Three peels reach it
|
|
116
|
+
# with a layer to spare, and bound the work on a large export.
|
|
117
|
+
MAX_DECODE_DEPTH = 3
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
def _try_b64_decode(run: bytes) -> bytes | None:
|
|
121
|
+
"""Decode a base64 / base64url run, or None if it is not really base64.
|
|
122
|
+
|
|
123
|
+
Only returns a decode that is overwhelmingly printable: a wrapped
|
|
124
|
+
credential (and the JSON or `user:token` around it) is text, whereas a
|
|
125
|
+
random high-entropy identifier that merely looks base64-shaped decodes to
|
|
126
|
+
binary noise not worth recursing into.
|
|
127
|
+
"""
|
|
128
|
+
body = run.rstrip(b"=").replace(b"-", b"+").replace(b"_", b"/")
|
|
129
|
+
body += b"=" * ((-len(body)) % 4)
|
|
130
|
+
try:
|
|
131
|
+
decoded = base64.b64decode(body, validate=True)
|
|
132
|
+
except (binascii.Error, ValueError):
|
|
133
|
+
return None
|
|
134
|
+
if len(decoded) < 3:
|
|
135
|
+
return None
|
|
136
|
+
printable = sum(1 for b in decoded if b in (9, 10, 13) or 32 <= b <= 126)
|
|
137
|
+
if printable / len(decoded) < 0.85:
|
|
138
|
+
return None
|
|
139
|
+
return decoded
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
def shannon_entropy(data: str) -> float:
|
|
143
|
+
"""Bits of entropy per character."""
|
|
144
|
+
if not data:
|
|
145
|
+
return 0.0
|
|
146
|
+
counts = Counter(data)
|
|
147
|
+
total = len(data)
|
|
148
|
+
return -sum(
|
|
149
|
+
(c / total) * math.log2(c / total) for c in counts.values()
|
|
150
|
+
)
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
def fingerprint(value: str) -> str:
|
|
154
|
+
"""Stable, non-reversible id for a secret. Safe to print, log and commit."""
|
|
155
|
+
return hashlib.sha256(value.encode("utf-8", "replace")).hexdigest()[:12]
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
def classify(value: str) -> str:
|
|
159
|
+
"""Shape of a candidate: guid | placeholder | jwt | opaque | low-entropy."""
|
|
160
|
+
stripped = value.strip().strip("\"'")
|
|
161
|
+
if GUID_RE.match(stripped):
|
|
162
|
+
return "guid"
|
|
163
|
+
lowered = stripped.lower()
|
|
164
|
+
if any(marker in lowered for marker in PLACEHOLDER_MARKERS):
|
|
165
|
+
return "placeholder"
|
|
166
|
+
if len(set(stripped)) <= 2:
|
|
167
|
+
return "placeholder"
|
|
168
|
+
if stripped.startswith("eyJ") and stripped.count(".") >= 2:
|
|
169
|
+
return "jwt"
|
|
170
|
+
if len(stripped) < MIN_OPAQUE_LEN:
|
|
171
|
+
return "low-entropy"
|
|
172
|
+
if shannon_entropy(stripped) < MIN_ENTROPY:
|
|
173
|
+
return "low-entropy"
|
|
174
|
+
return "opaque"
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
@dataclass
|
|
178
|
+
class Finding:
|
|
179
|
+
path: str
|
|
180
|
+
rule: str
|
|
181
|
+
shape: str
|
|
182
|
+
fingerprint: str
|
|
183
|
+
length: int
|
|
184
|
+
entropy: float
|
|
185
|
+
offset: int
|
|
186
|
+
severity: str
|
|
187
|
+
|
|
188
|
+
def render(self) -> str:
|
|
189
|
+
return (
|
|
190
|
+
f" {self.severity:<10} {self.rule:<24} shape={self.shape:<11} "
|
|
191
|
+
f"sha256:{self.fingerprint} len={self.length:<4} "
|
|
192
|
+
f"entropy={self.entropy:.2f} @byte {self.offset}"
|
|
193
|
+
)
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
def _decode(raw: bytes) -> str:
|
|
197
|
+
return raw.decode("utf-8", "replace")
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
def scan_bytes(
|
|
201
|
+
blob: bytes, path: str, base_offset: int = 0, _depth: int = 0
|
|
202
|
+
) -> list[Finding]:
|
|
203
|
+
"""Apply every rule to one chunk of bytes, then to base64-wrapped payloads.
|
|
204
|
+
|
|
205
|
+
A Kubernetes `dockerconfigjson` Secret hides its registry token two base64
|
|
206
|
+
layers deep, so the literal rules never see it on the raw bytes. After the
|
|
207
|
+
direct pass, decode any long base64 run and re-scan the result, down to
|
|
208
|
+
MAX_DECODE_DEPTH layers.
|
|
209
|
+
"""
|
|
210
|
+
findings: list[Finding] = []
|
|
211
|
+
for rule_name, pattern, entropy_gated in RULES:
|
|
212
|
+
for match in pattern.finditer(blob):
|
|
213
|
+
# Group 1 when the rule captures the value separately
|
|
214
|
+
# (Authorization headers), else the whole match.
|
|
215
|
+
raw = match.group(1) if pattern.groups else match.group(0)
|
|
216
|
+
value = _decode(raw)
|
|
217
|
+
shape = classify(value)
|
|
218
|
+
|
|
219
|
+
if shape in ("guid", "placeholder", "low-entropy"):
|
|
220
|
+
# A GUID after Bearer is a PROCESIO variable reference; a
|
|
221
|
+
# placeholder is documentation. Neither is a secret.
|
|
222
|
+
if entropy_gated or shape != "low-entropy":
|
|
223
|
+
continue
|
|
224
|
+
|
|
225
|
+
if rule_name == "private-key-pem":
|
|
226
|
+
severity = "CRITICAL"
|
|
227
|
+
elif rule_name in IDENTIFIER_ONLY:
|
|
228
|
+
severity = "INFO"
|
|
229
|
+
else:
|
|
230
|
+
severity = "CRITICAL"
|
|
231
|
+
|
|
232
|
+
findings.append(
|
|
233
|
+
Finding(
|
|
234
|
+
path=path,
|
|
235
|
+
rule=rule_name,
|
|
236
|
+
shape=shape,
|
|
237
|
+
fingerprint=fingerprint(value),
|
|
238
|
+
length=len(value),
|
|
239
|
+
entropy=round(shannon_entropy(value), 2),
|
|
240
|
+
offset=base_offset + match.start(),
|
|
241
|
+
severity=severity,
|
|
242
|
+
)
|
|
243
|
+
)
|
|
244
|
+
|
|
245
|
+
if _depth < MAX_DECODE_DEPTH:
|
|
246
|
+
for run in _B64_RUN.finditer(blob):
|
|
247
|
+
decoded = _try_b64_decode(run.group(0))
|
|
248
|
+
if decoded is None:
|
|
249
|
+
continue
|
|
250
|
+
for nested in scan_bytes(decoded, path, 0, _depth + 1):
|
|
251
|
+
# Byte offsets inside a decoded blob do not map back to the
|
|
252
|
+
# file; pin the finding to the wrapper run the reviewer scrubs.
|
|
253
|
+
nested.offset = base_offset + run.start()
|
|
254
|
+
findings.append(nested)
|
|
255
|
+
return findings
|
|
256
|
+
|
|
257
|
+
|
|
258
|
+
def scan_file(path: Path, display: str | None = None) -> list[Finding]:
|
|
259
|
+
"""Scan one file with overlapping windows.
|
|
260
|
+
|
|
261
|
+
Never reads the whole file into memory and never splits on newlines, so a
|
|
262
|
+
30 MB single-line JSON export is scanned exactly like any other file.
|
|
263
|
+
"""
|
|
264
|
+
display = display or str(path)
|
|
265
|
+
findings: list[Finding] = []
|
|
266
|
+
seen: set[tuple[str, str, str]] = set()
|
|
267
|
+
|
|
268
|
+
try:
|
|
269
|
+
size = path.stat().st_size
|
|
270
|
+
except OSError:
|
|
271
|
+
return findings
|
|
272
|
+
if size == 0:
|
|
273
|
+
return findings
|
|
274
|
+
|
|
275
|
+
with path.open("rb") as handle:
|
|
276
|
+
offset = 0
|
|
277
|
+
carry = b""
|
|
278
|
+
carry_offset = 0
|
|
279
|
+
while True:
|
|
280
|
+
chunk = handle.read(CHUNK_BYTES)
|
|
281
|
+
if not chunk:
|
|
282
|
+
break
|
|
283
|
+
window = carry + chunk
|
|
284
|
+
window_offset = carry_offset if carry else offset
|
|
285
|
+
for finding in scan_bytes(window, display, window_offset):
|
|
286
|
+
# The overlap means a token near a boundary is matched twice.
|
|
287
|
+
key = (finding.rule, finding.fingerprint, str(finding.offset))
|
|
288
|
+
dedup = (finding.rule, finding.fingerprint, "")
|
|
289
|
+
if dedup in seen:
|
|
290
|
+
continue
|
|
291
|
+
seen.add(dedup)
|
|
292
|
+
findings.append(finding)
|
|
293
|
+
offset += len(chunk)
|
|
294
|
+
carry = window[-OVERLAP_BYTES:]
|
|
295
|
+
carry_offset = offset - len(carry)
|
|
296
|
+
return findings
|
|
297
|
+
|
|
298
|
+
|
|
299
|
+
def detect_vcs(root: Path) -> list[str]:
|
|
300
|
+
"""Which version-control systems govern this working copy.
|
|
301
|
+
|
|
302
|
+
This repo is deliberately dual-VCS - one team consumes it over Git, the
|
|
303
|
+
other over SVN - so "what gets published" has two answers, and a scanner
|
|
304
|
+
that knows only one of them is inoperative for the other team. That was
|
|
305
|
+
the bug: an SVN-only checkout has no `.git`, `git ls-files` exited 128,
|
|
306
|
+
and the guard raised instead of guarding.
|
|
307
|
+
|
|
308
|
+
Both are returned when both are present (the mirror host holds both
|
|
309
|
+
working copies). The union is scanned rather than either alone: a file
|
|
310
|
+
versioned on only one side still reaches that side's team.
|
|
311
|
+
|
|
312
|
+
`.git` is matched as a path, not a directory - a worktree or submodule
|
|
313
|
+
checkout carries a `.git` *file* pointing at the real git dir.
|
|
314
|
+
"""
|
|
315
|
+
found: list[str] = []
|
|
316
|
+
if (root / ".git").exists():
|
|
317
|
+
found.append("git")
|
|
318
|
+
if (root / ".svn").is_dir():
|
|
319
|
+
found.append("svn")
|
|
320
|
+
return found
|
|
321
|
+
|
|
322
|
+
|
|
323
|
+
class NoVersionControl(RuntimeError):
|
|
324
|
+
"""Raised when the scan scope cannot be determined from the working copy."""
|
|
325
|
+
|
|
326
|
+
|
|
327
|
+
def _decode_nul_list(payload: bytes) -> list[str]:
|
|
328
|
+
return [name.decode("utf-8") for name in payload.split(b"\0") if name]
|
|
329
|
+
|
|
330
|
+
|
|
331
|
+
def _run_vcs(cmd: list[str], root: Path) -> bytes:
|
|
332
|
+
"""Run a VCS query, turning a non-zero exit into a legible failure.
|
|
333
|
+
|
|
334
|
+
A CalledProcessError from deep inside the guard reads as "the scanner is
|
|
335
|
+
broken"; for a check whose whole job is to refuse to pass silently, the
|
|
336
|
+
failure has to say which command failed and in which working copy.
|
|
337
|
+
"""
|
|
338
|
+
result = subprocess.run(cmd, cwd=root, capture_output=True)
|
|
339
|
+
if result.returncode != 0:
|
|
340
|
+
raise NoVersionControl(
|
|
341
|
+
f"{' '.join(cmd[:2])} failed in {root} (exit {result.returncode}): "
|
|
342
|
+
+ (result.stderr.decode("utf-8", "replace").strip() or "no stderr")
|
|
343
|
+
)
|
|
344
|
+
return result.stdout
|
|
345
|
+
|
|
346
|
+
|
|
347
|
+
# --------------------------------------------------------------------------
|
|
348
|
+
# git
|
|
349
|
+
# --------------------------------------------------------------------------
|
|
350
|
+
|
|
351
|
+
def _git_tracked(root: Path) -> list[str]:
|
|
352
|
+
return _decode_nul_list(_run_vcs(["git", "ls-files", "-z"], root))
|
|
353
|
+
|
|
354
|
+
|
|
355
|
+
def _git_changed(root: Path) -> list[str]:
|
|
356
|
+
return _decode_nul_list(
|
|
357
|
+
_run_vcs(
|
|
358
|
+
["git", "diff", "--cached", "--name-only", "--diff-filter=ACM", "-z"],
|
|
359
|
+
root,
|
|
360
|
+
)
|
|
361
|
+
)
|
|
362
|
+
|
|
363
|
+
|
|
364
|
+
# --------------------------------------------------------------------------
|
|
365
|
+
# svn
|
|
366
|
+
# --------------------------------------------------------------------------
|
|
367
|
+
|
|
368
|
+
# `svn status` item kinds that are NOT part of what a commit publishes.
|
|
369
|
+
# Everything else is scanned, including kinds not listed here: for a guard,
|
|
370
|
+
# an unrecognised state must fall through to "scan it", never to "skip it".
|
|
371
|
+
SVN_UNPUBLISHED = frozenset(
|
|
372
|
+
{"unversioned", "ignored", "external", "missing", "deleted", "none"}
|
|
373
|
+
)
|
|
374
|
+
|
|
375
|
+
# Item kinds that represent a local change - the SVN answer to "staged".
|
|
376
|
+
SVN_LOCAL_CHANGE = frozenset({"added", "modified", "replaced", "conflicted", "merged"})
|
|
377
|
+
|
|
378
|
+
|
|
379
|
+
def _svn_status_entries(root: Path, verbose: bool) -> list[tuple[str, str]]:
|
|
380
|
+
"""(path, item-kind) for every entry `svn status` reports.
|
|
381
|
+
|
|
382
|
+
`--xml` rather than the columnar default: the plain output is fixed-width
|
|
383
|
+
and positional, which mis-parses a path containing spaces - and this tree
|
|
384
|
+
has them. `svn status` is a working-copy operation and needs no network,
|
|
385
|
+
unlike `svn list -R`, which queries the repository and would make the
|
|
386
|
+
guard fail offline and hang a pre-commit hook.
|
|
387
|
+
"""
|
|
388
|
+
cmd = ["svn", "status", "--xml", "--no-ignore"]
|
|
389
|
+
if verbose:
|
|
390
|
+
cmd.append("--verbose")
|
|
391
|
+
payload = _run_vcs(cmd, root)
|
|
392
|
+
|
|
393
|
+
entries: list[tuple[str, str]] = []
|
|
394
|
+
for entry in ElementTree.fromstring(payload).iter("entry"):
|
|
395
|
+
path = entry.get("path")
|
|
396
|
+
if not path or path == ".":
|
|
397
|
+
continue
|
|
398
|
+
status = entry.find("wc-status")
|
|
399
|
+
item = status.get("item", "") if status is not None else ""
|
|
400
|
+
entries.append((path, item))
|
|
401
|
+
return entries
|
|
402
|
+
|
|
403
|
+
|
|
404
|
+
def _svn_versioned(root: Path) -> list[str]:
|
|
405
|
+
"""Every file SVN has under version control in this working copy."""
|
|
406
|
+
return [
|
|
407
|
+
path
|
|
408
|
+
for path, item in _svn_status_entries(root, verbose=True)
|
|
409
|
+
if item not in SVN_UNPUBLISHED
|
|
410
|
+
]
|
|
411
|
+
|
|
412
|
+
|
|
413
|
+
def _svn_changed(root: Path) -> list[str]:
|
|
414
|
+
"""Locally changed files - what `svn commit` would send.
|
|
415
|
+
|
|
416
|
+
SVN has no index, so nothing is literally "staged"; the closest honest
|
|
417
|
+
equivalent is the set of local modifications.
|
|
418
|
+
"""
|
|
419
|
+
return [
|
|
420
|
+
path
|
|
421
|
+
for path, item in _svn_status_entries(root, verbose=False)
|
|
422
|
+
if item in SVN_LOCAL_CHANGE
|
|
423
|
+
]
|
|
424
|
+
|
|
425
|
+
|
|
426
|
+
# --------------------------------------------------------------------------
|
|
427
|
+
# backend-agnostic entry points
|
|
428
|
+
# --------------------------------------------------------------------------
|
|
429
|
+
|
|
430
|
+
# backend -> (full-scope enumerator, local-change enumerator)
|
|
431
|
+
_ENUMERATORS = {
|
|
432
|
+
"git": (_git_tracked, _git_changed),
|
|
433
|
+
"svn": (_svn_versioned, _svn_changed),
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
|
|
437
|
+
def _collect(root: Path, index: int) -> list[Path]:
|
|
438
|
+
backends = detect_vcs(root)
|
|
439
|
+
if not backends:
|
|
440
|
+
raise NoVersionControl(
|
|
441
|
+
f"no .git or .svn in {root} - cannot determine which files are "
|
|
442
|
+
"published, and a secret scan over an unknown scope proves nothing"
|
|
443
|
+
)
|
|
444
|
+
names: set[str] = set()
|
|
445
|
+
for backend in backends:
|
|
446
|
+
names.update(_ENUMERATORS[backend][index](root))
|
|
447
|
+
return sorted({(root / name) for name in names}, key=str)
|
|
448
|
+
|
|
449
|
+
|
|
450
|
+
def tracked_files(root: Path) -> list[Path]:
|
|
451
|
+
"""Every file this working copy publishes, so the guard covers exactly that.
|
|
452
|
+
|
|
453
|
+
Git or SVN, or the union of both when the machine holds both.
|
|
454
|
+
|
|
455
|
+
Files only. `git ls-files` never names a directory, but `svn status -v`
|
|
456
|
+
reports one entry per versioned directory too, and counting those as
|
|
457
|
+
"scanned" overstates the guard's coverage by a fifth of the tree.
|
|
458
|
+
"""
|
|
459
|
+
return [p for p in _collect(root, 0) if p.is_file()]
|
|
460
|
+
|
|
461
|
+
|
|
462
|
+
def staged_files(root: Path) -> list[Path]:
|
|
463
|
+
"""Files a commit from here would carry - the pre-commit hook's scope."""
|
|
464
|
+
return [p for p in _collect(root, 1) if p.is_file()]
|
|
465
|
+
|
|
466
|
+
|
|
467
|
+
def load_allowlist(root: Path) -> set[str]:
|
|
468
|
+
"""Fingerprints reviewed and accepted as non-secret.
|
|
469
|
+
|
|
470
|
+
Holds fingerprints, never values - so the allowlist itself is safe to
|
|
471
|
+
commit. Add an entry only after confirming the value is not live.
|
|
472
|
+
"""
|
|
473
|
+
path = root / ".secret-scan-allowlist"
|
|
474
|
+
if not path.exists():
|
|
475
|
+
return set()
|
|
476
|
+
entries = set()
|
|
477
|
+
for line in path.read_text(encoding="utf-8").splitlines():
|
|
478
|
+
line = line.split("#", 1)[0].strip()
|
|
479
|
+
if line:
|
|
480
|
+
entries.add(line)
|
|
481
|
+
return entries
|
|
482
|
+
|
|
483
|
+
|
|
484
|
+
def _is_vcs_internal(rel: str) -> bool:
|
|
485
|
+
"""VCS metadata directories, which are never published content.
|
|
486
|
+
|
|
487
|
+
`.svn` matters more than `.git` here: `.svn/pristine` holds a complete
|
|
488
|
+
copy of every versioned file, so a directory scan that descends into it
|
|
489
|
+
reports each finding twice and - worse - keeps reporting a secret out of
|
|
490
|
+
the pristine copy after the working file has been scrubbed, which reads
|
|
491
|
+
as "the scrub did not work".
|
|
492
|
+
"""
|
|
493
|
+
# Separators are normalised because `rel` falls back to a native
|
|
494
|
+
# absolute path when the target sits outside the repo root, and on
|
|
495
|
+
# Windows that arrives backslash-separated.
|
|
496
|
+
return any(
|
|
497
|
+
part in (".git", ".svn")
|
|
498
|
+
for part in rel.replace("\\", "/").split("/")
|
|
499
|
+
)
|
|
500
|
+
|
|
501
|
+
|
|
502
|
+
def scan_paths(paths: list[Path], root: Path) -> list[Finding]:
|
|
503
|
+
allowed = load_allowlist(root)
|
|
504
|
+
findings: list[Finding] = []
|
|
505
|
+
for path in paths:
|
|
506
|
+
if not path.is_file():
|
|
507
|
+
continue
|
|
508
|
+
try:
|
|
509
|
+
rel = path.relative_to(root).as_posix()
|
|
510
|
+
except ValueError:
|
|
511
|
+
rel = str(path)
|
|
512
|
+
if rel == ".secret-scan-allowlist" or _is_vcs_internal(rel):
|
|
513
|
+
continue
|
|
514
|
+
for finding in scan_file(path, rel):
|
|
515
|
+
if finding.fingerprint in allowed:
|
|
516
|
+
continue
|
|
517
|
+
findings.append(finding)
|
|
518
|
+
return findings
|
|
519
|
+
|
|
520
|
+
|
|
521
|
+
def main() -> int:
|
|
522
|
+
parser = argparse.ArgumentParser(
|
|
523
|
+
description="Scan for live-credential formats in tracked files."
|
|
524
|
+
)
|
|
525
|
+
parser.add_argument(
|
|
526
|
+
"--staged",
|
|
527
|
+
action="store_true",
|
|
528
|
+
help="Scan only files staged for commit (pre-commit hook mode).",
|
|
529
|
+
)
|
|
530
|
+
parser.add_argument(
|
|
531
|
+
"--path",
|
|
532
|
+
action="append",
|
|
533
|
+
default=[],
|
|
534
|
+
help="Scan a specific file or directory (repeatable).",
|
|
535
|
+
)
|
|
536
|
+
parser.add_argument("--json", action="store_true", help="Emit JSON.")
|
|
537
|
+
args = parser.parse_args()
|
|
538
|
+
|
|
539
|
+
if args.path:
|
|
540
|
+
targets: list[Path] = []
|
|
541
|
+
for entry in args.path:
|
|
542
|
+
p = Path(entry)
|
|
543
|
+
if not p.is_absolute():
|
|
544
|
+
p = REPO_ROOT / entry
|
|
545
|
+
targets.extend(sorted(q for q in p.rglob("*") if q.is_file()) if p.is_dir() else [p])
|
|
546
|
+
elif args.staged:
|
|
547
|
+
targets = staged_files(REPO_ROOT)
|
|
548
|
+
else:
|
|
549
|
+
targets = tracked_files(REPO_ROOT)
|
|
550
|
+
|
|
551
|
+
findings = scan_paths(targets, REPO_ROOT)
|
|
552
|
+
blocking = [f for f in findings if f.severity == "CRITICAL"]
|
|
553
|
+
|
|
554
|
+
if args.json:
|
|
555
|
+
print(json.dumps([asdict(f) for f in findings], indent=2))
|
|
556
|
+
else:
|
|
557
|
+
if not findings:
|
|
558
|
+
print(f"secret-scan: clean ({len(targets)} files scanned)")
|
|
559
|
+
else:
|
|
560
|
+
by_path: dict[str, list[Finding]] = {}
|
|
561
|
+
for f in findings:
|
|
562
|
+
by_path.setdefault(f.path, []).append(f)
|
|
563
|
+
print(
|
|
564
|
+
f"secret-scan: {len(findings)} finding(s) in "
|
|
565
|
+
f"{len(by_path)} file(s) of {len(targets)} scanned\n"
|
|
566
|
+
)
|
|
567
|
+
for path, group in sorted(by_path.items()):
|
|
568
|
+
print(f"{path}")
|
|
569
|
+
for f in sorted(group, key=lambda x: x.offset):
|
|
570
|
+
print(f.render())
|
|
571
|
+
print()
|
|
572
|
+
if blocking:
|
|
573
|
+
print(
|
|
574
|
+
"Values are never printed. Identify a secret by its sha256 "
|
|
575
|
+
"prefix.\nRotate it at the source, scrub the file, then "
|
|
576
|
+
"re-scan. If a finding is\nconfirmed not live, add its "
|
|
577
|
+
"fingerprint to .secret-scan-allowlist."
|
|
578
|
+
)
|
|
579
|
+
|
|
580
|
+
return 1 if blocking else 0
|
|
581
|
+
|
|
582
|
+
|
|
583
|
+
if __name__ == "__main__":
|
|
584
|
+
sys.exit(main())
|