keboola-cli 0.63.4__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.
- keboola_agent_cli/__init__.py +34 -0
- keboola_agent_cli/__main__.py +5 -0
- keboola_agent_cli/_ui_dist/assets/arc-DhFYIddx.js +2 -0
- keboola_agent_cli/_ui_dist/assets/arc-DhFYIddx.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/architecture-7EHR7CIX-hNCijx_H.js +1 -0
- keboola_agent_cli/_ui_dist/assets/architectureDiagram-3BPJPVTR-C6hUlprM.js +37 -0
- keboola_agent_cli/_ui_dist/assets/architectureDiagram-3BPJPVTR-C6hUlprM.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/array-BifhSqXX.js +2 -0
- keboola_agent_cli/_ui_dist/assets/array-BifhSqXX.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/blockDiagram-GPEHLZMM-DC7qY9i4.js +133 -0
- keboola_agent_cli/_ui_dist/assets/blockDiagram-GPEHLZMM-DC7qY9i4.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/c4Diagram-AAUBKEIU-5Lh44evt.js +11 -0
- keboola_agent_cli/_ui_dist/assets/c4Diagram-AAUBKEIU-5Lh44evt.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/channel-DBMrXlxx.js +2 -0
- keboola_agent_cli/_ui_dist/assets/channel-DBMrXlxx.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/chunk-2J33WTMH-Coy82EBh.js +2 -0
- keboola_agent_cli/_ui_dist/assets/chunk-2J33WTMH-Coy82EBh.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/chunk-3OPIFGDE-BQC5CRHI.js +63 -0
- keboola_agent_cli/_ui_dist/assets/chunk-3OPIFGDE-BQC5CRHI.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/chunk-4BX2VUAB-DUuEt70o.js +2 -0
- keboola_agent_cli/_ui_dist/assets/chunk-4BX2VUAB-DUuEt70o.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/chunk-55IACEB6-BvR-6chF.js +2 -0
- keboola_agent_cli/_ui_dist/assets/chunk-55IACEB6-BvR-6chF.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/chunk-5ZQYHXKU-BjcTN7ul.js +3 -0
- keboola_agent_cli/_ui_dist/assets/chunk-5ZQYHXKU-BjcTN7ul.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/chunk-727SXJPM-C0zxqqRN.js +207 -0
- keboola_agent_cli/_ui_dist/assets/chunk-727SXJPM-C0zxqqRN.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/chunk-AQP2D5EJ-CXf7rIlZ.js +232 -0
- keboola_agent_cli/_ui_dist/assets/chunk-AQP2D5EJ-CXf7rIlZ.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/chunk-BSJP7CBP-Oj_FO9Q7.js +2 -0
- keboola_agent_cli/_ui_dist/assets/chunk-BSJP7CBP-Oj_FO9Q7.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/chunk-CSCIHK7Q-CcTsLrFc.js +124 -0
- keboola_agent_cli/_ui_dist/assets/chunk-CSCIHK7Q-CcTsLrFc.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/chunk-FMBD7UC4-FH-zLkkW.js +16 -0
- keboola_agent_cli/_ui_dist/assets/chunk-FMBD7UC4-FH-zLkkW.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/chunk-L5ZTLDWV-B1Ky_e7O.js +2 -0
- keboola_agent_cli/_ui_dist/assets/chunk-L5ZTLDWV-B1Ky_e7O.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/chunk-ND2GUHAM-BHz1rpbm.js +2 -0
- keboola_agent_cli/_ui_dist/assets/chunk-ND2GUHAM-BHz1rpbm.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/chunk-NNHCCRGN-DlpIbxXb.js +160 -0
- keboola_agent_cli/_ui_dist/assets/chunk-NNHCCRGN-DlpIbxXb.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/chunk-NZK2D7GU-tnrSoegS.js +2 -0
- keboola_agent_cli/_ui_dist/assets/chunk-NZK2D7GU-tnrSoegS.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/chunk-O5CBEL6O-DxxqDH0l.js +71 -0
- keboola_agent_cli/_ui_dist/assets/chunk-O5CBEL6O-DxxqDH0l.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/chunk-QZHKN3VN-CSjc2gjj.js +2 -0
- keboola_agent_cli/_ui_dist/assets/chunk-QZHKN3VN-CSjc2gjj.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/classDiagram-4FO5ZUOK-BuZcZu85.js +2 -0
- keboola_agent_cli/_ui_dist/assets/classDiagram-4FO5ZUOK-BuZcZu85.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/classDiagram-v2-Q7XG4LA2-BuZcZu85.js +2 -0
- keboola_agent_cli/_ui_dist/assets/classDiagram-v2-Q7XG4LA2-BuZcZu85.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/cose-bilkent-S5V4N54A-Y0L8LDMa.js +2 -0
- keboola_agent_cli/_ui_dist/assets/cose-bilkent-S5V4N54A-Y0L8LDMa.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/cytoscape.esm-C8YCVR3_.js +322 -0
- keboola_agent_cli/_ui_dist/assets/cytoscape.esm-C8YCVR3_.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/dagre-BM42HDAG-UZ-9BTqF.js +5 -0
- keboola_agent_cli/_ui_dist/assets/dagre-BM42HDAG-UZ-9BTqF.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/dagre-Bx709z4p.js +2 -0
- keboola_agent_cli/_ui_dist/assets/dagre-Bx709z4p.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/defaultLocale-C8Fc0cco.js +2 -0
- keboola_agent_cli/_ui_dist/assets/defaultLocale-C8Fc0cco.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/diagram-2AECGRRQ-DoDQ60wi.js +44 -0
- keboola_agent_cli/_ui_dist/assets/diagram-2AECGRRQ-DoDQ60wi.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/diagram-5GNKFQAL-CMGFxpUs.js +11 -0
- keboola_agent_cli/_ui_dist/assets/diagram-5GNKFQAL-CMGFxpUs.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/diagram-KO2AKTUF-1uGDa-Iu.js +4 -0
- keboola_agent_cli/_ui_dist/assets/diagram-KO2AKTUF-1uGDa-Iu.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/diagram-LMA3HP47-XtFH7B51.js +25 -0
- keboola_agent_cli/_ui_dist/assets/diagram-LMA3HP47-XtFH7B51.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/diagram-OG6HWLK6-B4_Te1T5.js +25 -0
- keboola_agent_cli/_ui_dist/assets/diagram-OG6HWLK6-B4_Te1T5.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/dist-Di6zmlv0.js +2 -0
- keboola_agent_cli/_ui_dist/assets/dist-Di6zmlv0.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/erDiagram-TEJ5UH35-NjQkrdFt.js +86 -0
- keboola_agent_cli/_ui_dist/assets/erDiagram-TEJ5UH35-NjQkrdFt.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/eventmodeling-FCH6USID-BrJMIks8.js +1 -0
- keboola_agent_cli/_ui_dist/assets/flowDiagram-I6XJVG4X-CIr8DWl7.js +163 -0
- keboola_agent_cli/_ui_dist/assets/flowDiagram-I6XJVG4X-CIr8DWl7.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/ganttDiagram-6RSMTGT7-C1VY_xbQ.js +293 -0
- keboola_agent_cli/_ui_dist/assets/ganttDiagram-6RSMTGT7-C1VY_xbQ.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/gitGraph-WXDBUCRP-COacYjo-.js +1 -0
- keboola_agent_cli/_ui_dist/assets/gitGraphDiagram-PVQCEYII-DQT8-kg2.js +107 -0
- keboola_agent_cli/_ui_dist/assets/gitGraphDiagram-PVQCEYII-DQT8-kg2.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/graphlib-B8gBHxth.js +2 -0
- keboola_agent_cli/_ui_dist/assets/graphlib-B8gBHxth.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/index-CMq50kkV.css +1 -0
- keboola_agent_cli/_ui_dist/assets/index-D8W97DAz.js +118 -0
- keboola_agent_cli/_ui_dist/assets/index-D8W97DAz.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/info-J43DQDTF-DdCTRIzU.js +1 -0
- keboola_agent_cli/_ui_dist/assets/infoDiagram-5YYISTIA-C77rsoTp.js +3 -0
- keboola_agent_cli/_ui_dist/assets/infoDiagram-5YYISTIA-C77rsoTp.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/init-D6jRqBbL.js +2 -0
- keboola_agent_cli/_ui_dist/assets/init-D6jRqBbL.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/ishikawaDiagram-YF4QCWOH-BcTbXaLy.js +71 -0
- keboola_agent_cli/_ui_dist/assets/ishikawaDiagram-YF4QCWOH-BcTbXaLy.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/journeyDiagram-JHISSGLW-BejeAJQ_.js +140 -0
- keboola_agent_cli/_ui_dist/assets/journeyDiagram-JHISSGLW-BejeAJQ_.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/kanban-definition-UN3LZRKU-BRNz_UrH.js +90 -0
- keboola_agent_cli/_ui_dist/assets/kanban-definition-UN3LZRKU-BRNz_UrH.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/katex-C4eR7coU.js +258 -0
- keboola_agent_cli/_ui_dist/assets/katex-C4eR7coU.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/line-CzAQKFbJ.js +2 -0
- keboola_agent_cli/_ui_dist/assets/line-CzAQKFbJ.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/linear-DUNFFdck.js +2 -0
- keboola_agent_cli/_ui_dist/assets/linear-DUNFFdck.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/mermaid-parser.core-CpuBOkFa.js +5 -0
- keboola_agent_cli/_ui_dist/assets/mermaid-parser.core-CpuBOkFa.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/mindmap-definition-RKZ34NQL-9EJQNjH0.js +97 -0
- keboola_agent_cli/_ui_dist/assets/mindmap-definition-RKZ34NQL-9EJQNjH0.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/ordinal-hYBb2elL.js +2 -0
- keboola_agent_cli/_ui_dist/assets/ordinal-hYBb2elL.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/packet-YPE3B663-DLiiw_B2.js +1 -0
- keboola_agent_cli/_ui_dist/assets/path-BWPyau1x.js +2 -0
- keboola_agent_cli/_ui_dist/assets/path-BWPyau1x.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/pie-LRSECV5Y-CRoO8G1g.js +1 -0
- keboola_agent_cli/_ui_dist/assets/pieDiagram-4H26LBE5-XH4cy6Cb.js +31 -0
- keboola_agent_cli/_ui_dist/assets/pieDiagram-4H26LBE5-XH4cy6Cb.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/quadrantDiagram-W4KKPZXB-fdhc93U8.js +8 -0
- keboola_agent_cli/_ui_dist/assets/quadrantDiagram-W4KKPZXB-fdhc93U8.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/radar-GUYGQ44K-DAlLVJHm.js +1 -0
- keboola_agent_cli/_ui_dist/assets/requirementDiagram-4Y6WPE33-a94eP3R9.js +85 -0
- keboola_agent_cli/_ui_dist/assets/requirementDiagram-4Y6WPE33-a94eP3R9.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/rough.esm-CSKSodPl.js +2 -0
- keboola_agent_cli/_ui_dist/assets/rough.esm-CSKSodPl.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/sankeyDiagram-5OEKKPKP-jcBa02sp.js +41 -0
- keboola_agent_cli/_ui_dist/assets/sankeyDiagram-5OEKKPKP-jcBa02sp.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/sequenceDiagram-3UESZ5HK-A5-GGM-e.js +163 -0
- keboola_agent_cli/_ui_dist/assets/sequenceDiagram-3UESZ5HK-A5-GGM-e.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/src-ZI-V_AF0.js +2 -0
- keboola_agent_cli/_ui_dist/assets/src-ZI-V_AF0.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/stateDiagram-AJRCARHV-BKAA5rqE.js +2 -0
- keboola_agent_cli/_ui_dist/assets/stateDiagram-AJRCARHV-BKAA5rqE.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/stateDiagram-v2-BHNVJYJU-DnJwJBsE.js +2 -0
- keboola_agent_cli/_ui_dist/assets/stateDiagram-v2-BHNVJYJU-DnJwJBsE.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/timeline-definition-PNZ67QCA-Cy39jp8b.js +121 -0
- keboola_agent_cli/_ui_dist/assets/timeline-definition-PNZ67QCA-Cy39jp8b.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/treeView-BLDUP644-DbLYl23-.js +1 -0
- keboola_agent_cli/_ui_dist/assets/treemap-LRROVOQU-Bp0eGlOt.js +1 -0
- keboola_agent_cli/_ui_dist/assets/vennDiagram-CIIHVFJN-BGECKubd.js +35 -0
- keboola_agent_cli/_ui_dist/assets/vennDiagram-CIIHVFJN-BGECKubd.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/wardley-L42UT6IY-D4yH4jqS.js +1 -0
- keboola_agent_cli/_ui_dist/assets/wardleyDiagram-YWT4CUSO-D6XRG3cZ.js +79 -0
- keboola_agent_cli/_ui_dist/assets/wardleyDiagram-YWT4CUSO-D6XRG3cZ.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/xychartDiagram-2RQKCTM6-DRre-pfZ.js +8 -0
- keboola_agent_cli/_ui_dist/assets/xychartDiagram-2RQKCTM6-DRre-pfZ.js.map +1 -0
- keboola_agent_cli/_ui_dist/index.html +50 -0
- keboola_agent_cli/ai_client.py +83 -0
- keboola_agent_cli/auto_update.py +550 -0
- keboola_agent_cli/changelog.py +1198 -0
- keboola_agent_cli/cli.py +448 -0
- keboola_agent_cli/client.py +3422 -0
- keboola_agent_cli/commands/__init__.py +0 -0
- keboola_agent_cli/commands/_data_app_git.py +343 -0
- keboola_agent_cli/commands/_helpers.py +377 -0
- keboola_agent_cli/commands/_metadata_input.py +49 -0
- keboola_agent_cli/commands/_semantic_layer_crud.py +632 -0
- keboola_agent_cli/commands/_semantic_layer_helpers.py +44 -0
- keboola_agent_cli/commands/_semantic_layer_reference_data.py +247 -0
- keboola_agent_cli/commands/agent.py +968 -0
- keboola_agent_cli/commands/branch.py +423 -0
- keboola_agent_cli/commands/changelog.py +168 -0
- keboola_agent_cli/commands/component.py +216 -0
- keboola_agent_cli/commands/config.py +2442 -0
- keboola_agent_cli/commands/context.py +1481 -0
- keboola_agent_cli/commands/data_app.py +1279 -0
- keboola_agent_cli/commands/dev_portal.py +584 -0
- keboola_agent_cli/commands/doctor.py +37 -0
- keboola_agent_cli/commands/encrypt.py +145 -0
- keboola_agent_cli/commands/feature.py +311 -0
- keboola_agent_cli/commands/flow.py +948 -0
- keboola_agent_cli/commands/http_client.py +157 -0
- keboola_agent_cli/commands/init.py +279 -0
- keboola_agent_cli/commands/job.py +661 -0
- keboola_agent_cli/commands/kai.py +301 -0
- keboola_agent_cli/commands/lineage.py +1464 -0
- keboola_agent_cli/commands/org.py +292 -0
- keboola_agent_cli/commands/permissions.py +360 -0
- keboola_agent_cli/commands/project.py +1192 -0
- keboola_agent_cli/commands/repl.py +243 -0
- keboola_agent_cli/commands/schedule.py +340 -0
- keboola_agent_cli/commands/search.py +178 -0
- keboola_agent_cli/commands/semantic_layer.py +939 -0
- keboola_agent_cli/commands/serve.py +272 -0
- keboola_agent_cli/commands/sharing.py +340 -0
- keboola_agent_cli/commands/storage.py +2630 -0
- keboola_agent_cli/commands/stream.py +266 -0
- keboola_agent_cli/commands/sync.py +1277 -0
- keboola_agent_cli/commands/tool.py +206 -0
- keboola_agent_cli/commands/version.py +186 -0
- keboola_agent_cli/commands/workspace.py +635 -0
- keboola_agent_cli/config_store.py +582 -0
- keboola_agent_cli/constants.py +528 -0
- keboola_agent_cli/data_science_client.py +342 -0
- keboola_agent_cli/dev_portal_client.py +323 -0
- keboola_agent_cli/errors.py +248 -0
- keboola_agent_cli/http_base.py +315 -0
- keboola_agent_cli/json_utils.py +126 -0
- keboola_agent_cli/lib.py +536 -0
- keboola_agent_cli/manage_client.py +324 -0
- keboola_agent_cli/metastore_client.py +214 -0
- keboola_agent_cli/models.py +427 -0
- keboola_agent_cli/output.py +1084 -0
- keboola_agent_cli/permissions.py +469 -0
- keboola_agent_cli/py.typed +3 -0
- keboola_agent_cli/result_models.py +271 -0
- keboola_agent_cli/server/__init__.py +34 -0
- keboola_agent_cli/server/agent_runner.py +1289 -0
- keboola_agent_cli/server/agents_store.py +325 -0
- keboola_agent_cli/server/app.py +764 -0
- keboola_agent_cli/server/auth.py +117 -0
- keboola_agent_cli/server/dependencies.py +149 -0
- keboola_agent_cli/server/pricing.py +303 -0
- keboola_agent_cli/server/routers/__init__.py +1 -0
- keboola_agent_cli/server/routers/agents.py +616 -0
- keboola_agent_cli/server/routers/ai_chat.py +129 -0
- keboola_agent_cli/server/routers/branches.py +133 -0
- keboola_agent_cli/server/routers/components.py +48 -0
- keboola_agent_cli/server/routers/configs.py +507 -0
- keboola_agent_cli/server/routers/data_apps.py +384 -0
- keboola_agent_cli/server/routers/dev_portal.py +67 -0
- keboola_agent_cli/server/routers/encrypt.py +35 -0
- keboola_agent_cli/server/routers/feature.py +179 -0
- keboola_agent_cli/server/routers/flows.py +204 -0
- keboola_agent_cli/server/routers/health.py +53 -0
- keboola_agent_cli/server/routers/jobs.py +175 -0
- keboola_agent_cli/server/routers/kai.py +80 -0
- keboola_agent_cli/server/routers/lineage.py +226 -0
- keboola_agent_cli/server/routers/mcp.py +70 -0
- keboola_agent_cli/server/routers/members.py +170 -0
- keboola_agent_cli/server/routers/org.py +96 -0
- keboola_agent_cli/server/routers/projects.py +106 -0
- keboola_agent_cli/server/routers/schedules.py +54 -0
- keboola_agent_cli/server/routers/search.py +30 -0
- keboola_agent_cli/server/routers/semantic_layer.py +650 -0
- keboola_agent_cli/server/routers/sharing.py +86 -0
- keboola_agent_cli/server/routers/storage.py +574 -0
- keboola_agent_cli/server/routers/stream.py +100 -0
- keboola_agent_cli/server/routers/workspaces.py +302 -0
- keboola_agent_cli/server/run_broadcaster.py +329 -0
- keboola_agent_cli/server/sse.py +25 -0
- keboola_agent_cli/services/__init__.py +0 -0
- keboola_agent_cli/services/_encryption.py +217 -0
- keboola_agent_cli/services/_semantic_layer_cascade.py +147 -0
- keboola_agent_cli/services/_semantic_layer_crud.py +382 -0
- keboola_agent_cli/services/_semantic_layer_internals.py +1078 -0
- keboola_agent_cli/services/_semantic_layer_lookup.py +181 -0
- keboola_agent_cli/services/_semantic_layer_reference_data.py +217 -0
- keboola_agent_cli/services/_sync_bindings.py +456 -0
- keboola_agent_cli/services/_sync_branch.py +191 -0
- keboola_agent_cli/services/_sync_bulk.py +228 -0
- keboola_agent_cli/services/_sync_clone.py +163 -0
- keboola_agent_cli/services/_sync_models.py +97 -0
- keboola_agent_cli/services/_sync_push_ops.py +369 -0
- keboola_agent_cli/services/_sync_storage.py +376 -0
- keboola_agent_cli/services/_sync_writeback.py +167 -0
- keboola_agent_cli/services/agent_service.py +458 -0
- keboola_agent_cli/services/base.py +175 -0
- keboola_agent_cli/services/branch_service.py +588 -0
- keboola_agent_cli/services/component_service.py +694 -0
- keboola_agent_cli/services/config_service.py +2099 -0
- keboola_agent_cli/services/data_app_git_service.py +224 -0
- keboola_agent_cli/services/data_app_service.py +2082 -0
- keboola_agent_cli/services/deep_lineage_service.py +1322 -0
- keboola_agent_cli/services/dev_portal_service.py +345 -0
- keboola_agent_cli/services/doctor_service.py +445 -0
- keboola_agent_cli/services/encrypt_service.py +87 -0
- keboola_agent_cli/services/feature_service.py +268 -0
- keboola_agent_cli/services/flow_service.py +769 -0
- keboola_agent_cli/services/flow_validation.py +188 -0
- keboola_agent_cli/services/http_forwarder_service.py +236 -0
- keboola_agent_cli/services/job_idempotency_store.py +285 -0
- keboola_agent_cli/services/job_service.py +797 -0
- keboola_agent_cli/services/kai_service.py +367 -0
- keboola_agent_cli/services/lineage_service.py +274 -0
- keboola_agent_cli/services/mcp_service.py +1498 -0
- keboola_agent_cli/services/mcp_transport.py +259 -0
- keboola_agent_cli/services/member_service.py +593 -0
- keboola_agent_cli/services/org_service.py +619 -0
- keboola_agent_cli/services/project_service.py +947 -0
- keboola_agent_cli/services/repo_validate_service.py +767 -0
- keboola_agent_cli/services/schedule_service.py +731 -0
- keboola_agent_cli/services/search_service.py +331 -0
- keboola_agent_cli/services/semantic_layer_service.py +1497 -0
- keboola_agent_cli/services/sharing_service.py +307 -0
- keboola_agent_cli/services/storage_service.py +2524 -0
- keboola_agent_cli/services/stream_service.py +395 -0
- keboola_agent_cli/services/sync_service.py +2244 -0
- keboola_agent_cli/services/variables_service.py +447 -0
- keboola_agent_cli/services/version_service.py +1038 -0
- keboola_agent_cli/services/workspace_service.py +1103 -0
- keboola_agent_cli/stream_client.py +217 -0
- keboola_agent_cli/sync/__init__.py +1 -0
- keboola_agent_cli/sync/branch_mapping.py +174 -0
- keboola_agent_cli/sync/clone.py +211 -0
- keboola_agent_cli/sync/code_extraction.py +655 -0
- keboola_agent_cli/sync/config_format.py +290 -0
- keboola_agent_cli/sync/diff_engine.py +566 -0
- keboola_agent_cli/sync/git_utils.py +93 -0
- keboola_agent_cli/sync/manifest.py +162 -0
- keboola_agent_cli/sync/naming.py +90 -0
- keboola_agent_cli/sync/secrets.py +62 -0
- keboola_agent_cli/sync/sql_split.py +134 -0
- keboola_cli-0.63.4.dist-info/METADATA +308 -0
- keboola_cli-0.63.4.dist-info/RECORD +306 -0
- keboola_cli-0.63.4.dist-info/WHEEL +4 -0
- keboola_cli-0.63.4.dist-info/entry_points.txt +2 -0
|
@@ -0,0 +1,469 @@
|
|
|
1
|
+
"""Firewall-style permission engine for CLI commands and MCP tools.
|
|
2
|
+
|
|
3
|
+
Provides an operation registry mapping every CLI command and MCP tool category
|
|
4
|
+
to a risk level, and a PermissionEngine that evaluates allow/deny policies
|
|
5
|
+
with pattern matching (exact, glob, category).
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import fnmatch
|
|
9
|
+
|
|
10
|
+
from .errors import PermissionDeniedError
|
|
11
|
+
from .models import PermissionPolicy
|
|
12
|
+
|
|
13
|
+
# Risk categories for all CLI operations.
|
|
14
|
+
# read = no side effects, write = creates/modifies, destructive = deletes, admin = org-level
|
|
15
|
+
OPERATION_REGISTRY: dict[str, str] = {
|
|
16
|
+
# Project management
|
|
17
|
+
"project.add": "admin",
|
|
18
|
+
"project.list": "read",
|
|
19
|
+
"project.remove": "admin",
|
|
20
|
+
"project.edit": "admin",
|
|
21
|
+
"project.status": "read",
|
|
22
|
+
"project.refresh": "admin",
|
|
23
|
+
"project.description-get": "read",
|
|
24
|
+
"project.description-set": "write",
|
|
25
|
+
"project.use": "write",
|
|
26
|
+
"project.current": "read",
|
|
27
|
+
"project.info": "read",
|
|
28
|
+
"project.invite": "admin",
|
|
29
|
+
"project.member-list": "read",
|
|
30
|
+
"project.invitation-list": "read",
|
|
31
|
+
"project.invitation-cancel": "admin",
|
|
32
|
+
"project.member-remove": "destructive",
|
|
33
|
+
"project.member-set-role": "admin",
|
|
34
|
+
# Feature flags (super-admin manage token). Reads are safe; enabling a
|
|
35
|
+
# feature is an org-level decision (admin); removing one is destructive.
|
|
36
|
+
"feature.list": "read",
|
|
37
|
+
"feature.project-show": "read",
|
|
38
|
+
"feature.project-add": "admin",
|
|
39
|
+
"feature.project-remove": "destructive",
|
|
40
|
+
"feature.user-show": "read",
|
|
41
|
+
"feature.user-add": "admin",
|
|
42
|
+
"feature.user-remove": "destructive",
|
|
43
|
+
# Data Streams (OTLP). Listing/inspecting sources is read-only; creating a
|
|
44
|
+
# source provisions ingest infrastructure (write); deleting one is destructive.
|
|
45
|
+
"stream.list": "read",
|
|
46
|
+
"stream.detail": "read",
|
|
47
|
+
"stream.create-source": "write",
|
|
48
|
+
"stream.delete": "destructive",
|
|
49
|
+
# Config browsing & management
|
|
50
|
+
"config.list": "read",
|
|
51
|
+
"config.detail": "read",
|
|
52
|
+
"config.search": "read",
|
|
53
|
+
"config.update": "write",
|
|
54
|
+
"config.set-default-bucket": "write",
|
|
55
|
+
"config.rename": "write",
|
|
56
|
+
"config.delete": "destructive",
|
|
57
|
+
"config.new": "write",
|
|
58
|
+
"config.variables-set": "write",
|
|
59
|
+
"config.variables-get": "read",
|
|
60
|
+
"config.variables-clear": "destructive",
|
|
61
|
+
"config.metadata-list": "read",
|
|
62
|
+
"config.get-metadata": "read",
|
|
63
|
+
"config.set-metadata": "write",
|
|
64
|
+
"config.delete-metadata": "destructive",
|
|
65
|
+
"config.set-folder": "write",
|
|
66
|
+
"config.row-create": "write",
|
|
67
|
+
"config.row-update": "write",
|
|
68
|
+
"config.row-delete": "destructive",
|
|
69
|
+
"config.oauth-url": "read",
|
|
70
|
+
# Job history
|
|
71
|
+
"job.list": "read",
|
|
72
|
+
"job.detail": "read",
|
|
73
|
+
"job.run": "write",
|
|
74
|
+
"job.terminate": "destructive",
|
|
75
|
+
# Lineage
|
|
76
|
+
"lineage.build": "read",
|
|
77
|
+
"lineage.info": "read",
|
|
78
|
+
"lineage.show": "read",
|
|
79
|
+
"lineage.server": "read",
|
|
80
|
+
# Sharing
|
|
81
|
+
"sharing.list": "read",
|
|
82
|
+
"sharing.edges": "read",
|
|
83
|
+
"sharing.share": "write",
|
|
84
|
+
"sharing.unshare": "write",
|
|
85
|
+
"sharing.link": "write",
|
|
86
|
+
"sharing.unlink": "write",
|
|
87
|
+
# Organization
|
|
88
|
+
"org.setup": "admin",
|
|
89
|
+
# Branch lifecycle
|
|
90
|
+
"branch.list": "read",
|
|
91
|
+
"branch.create": "write",
|
|
92
|
+
"branch.use": "write",
|
|
93
|
+
"branch.reset": "write",
|
|
94
|
+
"branch.delete": "destructive",
|
|
95
|
+
"branch.merge": "write",
|
|
96
|
+
"branch.metadata-list": "read",
|
|
97
|
+
"branch.metadata-get": "read",
|
|
98
|
+
"branch.metadata-set": "write",
|
|
99
|
+
"branch.metadata-delete": "destructive",
|
|
100
|
+
# Workspace lifecycle
|
|
101
|
+
"workspace.create": "write",
|
|
102
|
+
"workspace.list": "read",
|
|
103
|
+
"workspace.detail": "read",
|
|
104
|
+
"workspace.delete": "destructive",
|
|
105
|
+
"workspace.password": "read",
|
|
106
|
+
"workspace.load": "write",
|
|
107
|
+
"workspace.query": "write",
|
|
108
|
+
"workspace.from-transformation": "write",
|
|
109
|
+
"workspace.gc": "destructive",
|
|
110
|
+
# Scheduled agent tasks (kbagent agent ...; touches only local
|
|
111
|
+
# agents.json + spawns subprocesses via the runner).
|
|
112
|
+
"agent.list": "read",
|
|
113
|
+
"agent.show": "read",
|
|
114
|
+
"agent.create": "write",
|
|
115
|
+
"agent.update": "write",
|
|
116
|
+
"agent.delete": "destructive",
|
|
117
|
+
# Run is classified write -- ai_agent/cli_command actions can mutate
|
|
118
|
+
# external state via subprocesses; deny-writes should block this.
|
|
119
|
+
"agent.run": "write",
|
|
120
|
+
"agent.runs": "read",
|
|
121
|
+
"agent.run-detail": "read",
|
|
122
|
+
"agent.run-events": "read",
|
|
123
|
+
"agent.test": "write",
|
|
124
|
+
"agent.cron-preview": "read",
|
|
125
|
+
"agent.prompt-improve": "write",
|
|
126
|
+
# MCP tools
|
|
127
|
+
"tool.list": "read",
|
|
128
|
+
"tool.call": "write",
|
|
129
|
+
# Kai (Keboola AI Assistant)
|
|
130
|
+
"kai.ping": "read",
|
|
131
|
+
"kai.preflight": "read",
|
|
132
|
+
"kai.ask": "read",
|
|
133
|
+
"kai.chat": "write",
|
|
134
|
+
"kai.chat-detail": "read",
|
|
135
|
+
"kai.history": "read",
|
|
136
|
+
# Component discovery
|
|
137
|
+
"component.list": "read",
|
|
138
|
+
"component.detail": "read",
|
|
139
|
+
# Developer Portal (since 0.48.0)
|
|
140
|
+
# Developer Portal — top-level commands on `dev-portal` (the identity
|
|
141
|
+
# sub-app's leaves are listed separately below under dev-portal.identity.*).
|
|
142
|
+
# Categories follow data-app.secrets-* precedent: credential add/edit are
|
|
143
|
+
# `write`, not `admin` (admin is reserved for org-level operations).
|
|
144
|
+
"dev-portal.identity": "read", # parent-callback descent (allow into sub-app)
|
|
145
|
+
"dev-portal.list": "read",
|
|
146
|
+
"dev-portal.get": "read",
|
|
147
|
+
"dev-portal.create": "write",
|
|
148
|
+
"dev-portal.patch": "write",
|
|
149
|
+
"dev-portal.upload-icon": "write",
|
|
150
|
+
"dev-portal.publish": "admin",
|
|
151
|
+
"dev-portal.deprecate": "destructive",
|
|
152
|
+
# Data apps (Data Science API + keboola.data-apps Storage component)
|
|
153
|
+
"data-app.list": "read",
|
|
154
|
+
"data-app.detail": "read",
|
|
155
|
+
"data-app.password": "read",
|
|
156
|
+
"data-app.logs": "read",
|
|
157
|
+
"data-app.create": "write",
|
|
158
|
+
"data-app.deploy": "write",
|
|
159
|
+
"data-app.start": "write",
|
|
160
|
+
"data-app.stop": "write",
|
|
161
|
+
"data-app.delete": "destructive",
|
|
162
|
+
# Data apps - secrets + validate-repo (new in 0.28.0)
|
|
163
|
+
"data-app.secrets-set": "write",
|
|
164
|
+
"data-app.secrets-list": "read",
|
|
165
|
+
"data-app.secrets-get": "read",
|
|
166
|
+
"data-app.secrets-remove": "destructive",
|
|
167
|
+
"data-app.validate-repo": "read",
|
|
168
|
+
# Data apps - git-repo introspection + managed-repo credentials
|
|
169
|
+
"data-app.git-repo": "read",
|
|
170
|
+
"data-app.git-branches": "read",
|
|
171
|
+
"data-app.git-entrypoints": "read",
|
|
172
|
+
"data-app.git-credentials": "read",
|
|
173
|
+
"data-app.git-credentials-create": "write",
|
|
174
|
+
# Developer Portal — identity sub-app leaves (composed by the
|
|
175
|
+
# identity_app callback as "dev-portal.identity.<subcommand>")
|
|
176
|
+
"dev-portal.identity.add": "write",
|
|
177
|
+
"dev-portal.identity.list": "read",
|
|
178
|
+
"dev-portal.identity.remove": "write",
|
|
179
|
+
"dev-portal.identity.edit": "write",
|
|
180
|
+
"dev-portal.identity.use": "write",
|
|
181
|
+
"dev-portal.identity.current": "read",
|
|
182
|
+
"dev-portal.identity.verify": "read",
|
|
183
|
+
# Storage browsing
|
|
184
|
+
"storage.buckets": "read",
|
|
185
|
+
"storage.bucket-detail": "read",
|
|
186
|
+
"storage.tables": "read",
|
|
187
|
+
"storage.table-detail": "read",
|
|
188
|
+
"storage.download-table": "read",
|
|
189
|
+
# Storage write
|
|
190
|
+
"storage.create-bucket": "write",
|
|
191
|
+
"storage.create-table": "write",
|
|
192
|
+
"storage.add-column": "write",
|
|
193
|
+
"storage.upload-table": "write",
|
|
194
|
+
# clone-table pulls a prod table into a dev branch (materialization); it
|
|
195
|
+
# creates a branch-local copy and never deletes -- write, not destructive.
|
|
196
|
+
"storage.clone-table": "write",
|
|
197
|
+
# Storage files
|
|
198
|
+
"storage.files": "read",
|
|
199
|
+
"storage.file-detail": "read",
|
|
200
|
+
"storage.file-download": "read",
|
|
201
|
+
"storage.file-upload": "write",
|
|
202
|
+
"storage.file-tag": "write",
|
|
203
|
+
"storage.load-file": "write",
|
|
204
|
+
"storage.unload-table": "read",
|
|
205
|
+
# Storage destructive
|
|
206
|
+
"storage.delete-table": "destructive",
|
|
207
|
+
"storage.delete-column": "destructive",
|
|
208
|
+
"storage.delete-bucket": "destructive",
|
|
209
|
+
"storage.file-delete": "destructive",
|
|
210
|
+
"storage.swap-tables": "destructive",
|
|
211
|
+
"storage.truncate-table": "destructive",
|
|
212
|
+
# Storage descriptions
|
|
213
|
+
"storage.describe-bucket": "write",
|
|
214
|
+
"storage.describe-table": "write",
|
|
215
|
+
"storage.describe-column": "write",
|
|
216
|
+
"storage.describe-batch": "write",
|
|
217
|
+
# Encryption
|
|
218
|
+
"encrypt.values": "write",
|
|
219
|
+
# Semantic layer (metastore) — new in 0.41.0
|
|
220
|
+
"semantic-layer.show": "read",
|
|
221
|
+
"semantic-layer.validate": "read",
|
|
222
|
+
"semantic-layer.export": "read",
|
|
223
|
+
"semantic-layer.diff": "read",
|
|
224
|
+
"semantic-layer.search-context": "read",
|
|
225
|
+
"semantic-layer.get-context": "read",
|
|
226
|
+
# The `model` sub-app: the parent `semantic-layer` callback fires first
|
|
227
|
+
# with ctx.invoked_subcommand == "model" and synthesizes operation key
|
|
228
|
+
# ``semantic-layer.model``. We expose that key at the LEAST-privileged
|
|
229
|
+
# leaf risk (read) so the parent permits descent — the model sub-app's
|
|
230
|
+
# own callback then runs with the per-leaf keys below and enforces the
|
|
231
|
+
# actual gate. Without the parent-level key the fail-closed default
|
|
232
|
+
# treats ``semantic-layer.model`` as ``write`` and denies even
|
|
233
|
+
# ``model list`` under ``--deny-writes``.
|
|
234
|
+
"semantic-layer.model": "read",
|
|
235
|
+
"semantic-layer.model.list": "read",
|
|
236
|
+
"semantic-layer.model.create": "write",
|
|
237
|
+
"semantic-layer.model.delete": "destructive",
|
|
238
|
+
# The add/edit/remove sub-apps: same parent-callback pattern as `model`
|
|
239
|
+
# above -- the parent semantic-layer callback fires with the collapsed
|
|
240
|
+
# key, then the sub-app callback composes per-leaf operation keys via
|
|
241
|
+
# the standard ``check_cli_permission`` helper. Every leaf inside one
|
|
242
|
+
# sub-app shares the same risk class (add=write, edit=write,
|
|
243
|
+
# remove=destructive), so the per-leaf keys all carry that class.
|
|
244
|
+
"semantic-layer.add": "write",
|
|
245
|
+
"semantic-layer.add.metric": "write",
|
|
246
|
+
"semantic-layer.add.dataset": "write",
|
|
247
|
+
"semantic-layer.add.relationship": "write",
|
|
248
|
+
"semantic-layer.add.constraint": "write",
|
|
249
|
+
"semantic-layer.add.glossary": "write",
|
|
250
|
+
"semantic-layer.edit": "write",
|
|
251
|
+
"semantic-layer.edit.metric": "write",
|
|
252
|
+
"semantic-layer.edit.dataset": "write",
|
|
253
|
+
"semantic-layer.edit.constraint": "write",
|
|
254
|
+
"semantic-layer.edit.relationship": "write",
|
|
255
|
+
"semantic-layer.edit.glossary": "write",
|
|
256
|
+
"semantic-layer.import": "write",
|
|
257
|
+
"semantic-layer.promote": "write",
|
|
258
|
+
"semantic-layer.build": "write",
|
|
259
|
+
# `token --encrypt` calls EncryptService, same blast radius as
|
|
260
|
+
# `encrypt.values` which is `write`. Classified `write` for parity:
|
|
261
|
+
# users opting out via --deny-writes block both consistently.
|
|
262
|
+
"semantic-layer.token": "write",
|
|
263
|
+
"semantic-layer.remove": "destructive",
|
|
264
|
+
"semantic-layer.remove.metric": "destructive",
|
|
265
|
+
"semantic-layer.remove.dataset": "destructive",
|
|
266
|
+
"semantic-layer.remove.constraint": "destructive",
|
|
267
|
+
"semantic-layer.remove.relationship": "destructive",
|
|
268
|
+
"semantic-layer.remove.glossary": "destructive",
|
|
269
|
+
# `reference-data` sub-app: dimension-member records (e.g. a Chart of
|
|
270
|
+
# Accounts). Parent key at the least-privileged level (read) so the
|
|
271
|
+
# top-level `semantic-layer` callback does not over-block `list` / `get`;
|
|
272
|
+
# per-leaf keys carry the real classification.
|
|
273
|
+
"semantic-layer.reference-data": "read",
|
|
274
|
+
"semantic-layer.reference-data.list": "read",
|
|
275
|
+
"semantic-layer.reference-data.get": "read",
|
|
276
|
+
"semantic-layer.reference-data.set": "write",
|
|
277
|
+
"semantic-layer.reference-data.delete": "destructive",
|
|
278
|
+
# Raw HTTP client against `kbagent serve` (used by AI subprocesses).
|
|
279
|
+
# Categorised by the underlying HTTP method: GET = read, mutating verbs
|
|
280
|
+
# = write. The serve's own routes enforce their own permissions on top.
|
|
281
|
+
"http.get": "read",
|
|
282
|
+
"http.post": "write",
|
|
283
|
+
"http.patch": "write",
|
|
284
|
+
"http.delete": "destructive",
|
|
285
|
+
# Sync / git workflow
|
|
286
|
+
"sync.init": "read",
|
|
287
|
+
"sync.pull": "read",
|
|
288
|
+
"sync.status": "read",
|
|
289
|
+
"sync.diff": "read",
|
|
290
|
+
"sync.push": "write",
|
|
291
|
+
"sync.clone": "write",
|
|
292
|
+
"sync.branch-link": "write",
|
|
293
|
+
"sync.branch-unlink": "write",
|
|
294
|
+
"sync.branch-status": "read",
|
|
295
|
+
# Flow operations
|
|
296
|
+
"flow.list": "read",
|
|
297
|
+
"flow.detail": "read",
|
|
298
|
+
"flow.schema": "read",
|
|
299
|
+
"flow.validate": "read",
|
|
300
|
+
"flow.new": "write",
|
|
301
|
+
"flow.update": "write",
|
|
302
|
+
"flow.delete": "destructive",
|
|
303
|
+
"flow.schedule": "write",
|
|
304
|
+
"flow.schedule-remove": "destructive",
|
|
305
|
+
# Schedule discovery / audit (read-only)
|
|
306
|
+
"schedule.list": "read",
|
|
307
|
+
"schedule.detail": "read",
|
|
308
|
+
"schedule.find": "read",
|
|
309
|
+
# Top-level commands
|
|
310
|
+
"search": "read",
|
|
311
|
+
"init": "admin",
|
|
312
|
+
"doctor": "read",
|
|
313
|
+
"version": "read",
|
|
314
|
+
"update": "admin",
|
|
315
|
+
"changelog": "read",
|
|
316
|
+
"context": "read",
|
|
317
|
+
"repl": "read",
|
|
318
|
+
"serve": "admin",
|
|
319
|
+
# Permissions (always allowed -- listed for completeness)
|
|
320
|
+
"permissions.list": "read",
|
|
321
|
+
"permissions.show": "read",
|
|
322
|
+
"permissions.set": "admin",
|
|
323
|
+
"permissions.reset": "admin",
|
|
324
|
+
"permissions.check": "read",
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
# Prefixes for classifying MCP tools (mirrors mcp_service.py WRITE_PREFIXES)
|
|
328
|
+
_MCP_WRITE_PREFIXES = ("create_", "update_", "add_", "set_")
|
|
329
|
+
_MCP_DESTRUCTIVE_PREFIXES = ("delete_", "remove_")
|
|
330
|
+
|
|
331
|
+
|
|
332
|
+
def classify_mcp_tool(tool_name: str) -> str:
|
|
333
|
+
"""Classify an MCP tool by its name prefix.
|
|
334
|
+
|
|
335
|
+
Returns:
|
|
336
|
+
Risk category: 'read', 'write', or 'destructive'.
|
|
337
|
+
"""
|
|
338
|
+
if tool_name.startswith(_MCP_DESTRUCTIVE_PREFIXES):
|
|
339
|
+
return "destructive"
|
|
340
|
+
if tool_name.startswith(_MCP_WRITE_PREFIXES):
|
|
341
|
+
return "write"
|
|
342
|
+
return "read"
|
|
343
|
+
|
|
344
|
+
|
|
345
|
+
def _matches_pattern(operation: str, pattern: str) -> bool:
|
|
346
|
+
"""Check if an operation matches a permission pattern.
|
|
347
|
+
|
|
348
|
+
Supports:
|
|
349
|
+
- Exact: 'branch.delete' matches 'branch.delete'
|
|
350
|
+
- Glob: 'sync.*' matches 'sync.push', 'tool:create_*' matches 'tool:create_config'
|
|
351
|
+
- Category 'cli:read' matches all CLI ops with category 'read'
|
|
352
|
+
- Category 'cli:write' matches all CLI ops with category 'write' or 'destructive' or 'admin'
|
|
353
|
+
- Category 'tool:read' matches all MCP tools (tool:*) with read classification
|
|
354
|
+
- Category 'tool:write' matches all MCP tools (tool:*) with write or destructive classification
|
|
355
|
+
"""
|
|
356
|
+
# Category patterns: cli:read, cli:write, tool:read, tool:write
|
|
357
|
+
if pattern in ("cli:read", "cli:write", "cli:destructive", "cli:admin"):
|
|
358
|
+
# cli:* patterns only match CLI operations, never MCP tools
|
|
359
|
+
if operation.startswith("tool:"):
|
|
360
|
+
return False
|
|
361
|
+
target_category = pattern.split(":")[1]
|
|
362
|
+
# Fail-closed: unknown CLI ops default to 'write' so they are
|
|
363
|
+
# blocked by cli:write policies. This prevents new commands from
|
|
364
|
+
# bypassing restrictions if OPERATION_REGISTRY is not updated.
|
|
365
|
+
op_category = OPERATION_REGISTRY.get(operation, "write")
|
|
366
|
+
if target_category == "write":
|
|
367
|
+
# cli:write matches write, destructive, and admin
|
|
368
|
+
return op_category in ("write", "destructive", "admin")
|
|
369
|
+
return op_category == target_category
|
|
370
|
+
|
|
371
|
+
if pattern in ("tool:read", "tool:write", "tool:destructive"):
|
|
372
|
+
target_category = pattern.split(":")[1]
|
|
373
|
+
if not operation.startswith("tool:"):
|
|
374
|
+
return False
|
|
375
|
+
tool_name = operation[5:] # strip 'tool:' prefix
|
|
376
|
+
tool_category = classify_mcp_tool(tool_name)
|
|
377
|
+
if target_category == "write":
|
|
378
|
+
# tool:write matches write and destructive
|
|
379
|
+
return tool_category in ("write", "destructive")
|
|
380
|
+
return tool_category == target_category
|
|
381
|
+
|
|
382
|
+
# Exact or glob match
|
|
383
|
+
return fnmatch.fnmatch(operation, pattern)
|
|
384
|
+
|
|
385
|
+
|
|
386
|
+
class PermissionEngine:
|
|
387
|
+
"""Evaluates permission policies against operations.
|
|
388
|
+
|
|
389
|
+
Thread-safe and stateless per call -- safe to share across contexts.
|
|
390
|
+
"""
|
|
391
|
+
|
|
392
|
+
def __init__(self, policy: PermissionPolicy | None) -> None:
|
|
393
|
+
self._policy = policy
|
|
394
|
+
|
|
395
|
+
@property
|
|
396
|
+
def active(self) -> bool:
|
|
397
|
+
"""Whether a permission policy is configured."""
|
|
398
|
+
return self._policy is not None
|
|
399
|
+
|
|
400
|
+
def is_allowed(self, operation: str) -> bool:
|
|
401
|
+
"""Check if an operation is allowed by the active policy.
|
|
402
|
+
|
|
403
|
+
Returns True if no policy is configured (no restrictions).
|
|
404
|
+
|
|
405
|
+
Fail-closed: CLI operations not in OPERATION_REGISTRY are treated as
|
|
406
|
+
'write' for category matching. This ensures new commands added without
|
|
407
|
+
updating the registry are blocked by policies like 'deny cli:write'.
|
|
408
|
+
"""
|
|
409
|
+
if self._policy is None:
|
|
410
|
+
return True
|
|
411
|
+
|
|
412
|
+
# permissions.* commands are always allowed (prevent lockout)
|
|
413
|
+
if operation.startswith("permissions."):
|
|
414
|
+
return True
|
|
415
|
+
|
|
416
|
+
denied = any(_matches_pattern(operation, p) for p in self._policy.deny)
|
|
417
|
+
allowed = any(_matches_pattern(operation, p) for p in self._policy.allow)
|
|
418
|
+
|
|
419
|
+
if self._policy.mode == "allow":
|
|
420
|
+
# Default-allow: blocked only if deny matches (and allow doesn't override)
|
|
421
|
+
return not (denied and not allowed)
|
|
422
|
+
# Default-deny: allowed only if allow matches (and deny doesn't override)
|
|
423
|
+
return bool(allowed and not denied)
|
|
424
|
+
|
|
425
|
+
def check_or_raise(self, operation: str) -> None:
|
|
426
|
+
"""Check if an operation is allowed, raising PermissionDeniedError if not."""
|
|
427
|
+
if not self.is_allowed(operation):
|
|
428
|
+
raise PermissionDeniedError(operation)
|
|
429
|
+
|
|
430
|
+
def list_operations(self) -> list[dict[str, str]]:
|
|
431
|
+
"""List all known operations with their category and allowed/denied status.
|
|
432
|
+
|
|
433
|
+
Returns a list of dicts with keys: name, category, status ('allowed' or 'denied').
|
|
434
|
+
Includes both CLI operations and MCP tool category summaries.
|
|
435
|
+
"""
|
|
436
|
+
ops: list[dict[str, str]] = []
|
|
437
|
+
|
|
438
|
+
# CLI operations
|
|
439
|
+
for name, category in sorted(OPERATION_REGISTRY.items()):
|
|
440
|
+
status = "allowed" if self.is_allowed(name) else "denied"
|
|
441
|
+
ops.append({"name": name, "type": "cli", "category": category, "status": status})
|
|
442
|
+
|
|
443
|
+
# MCP tool categories (virtual entries for reference)
|
|
444
|
+
mcp_categories = [
|
|
445
|
+
("tool:read", "read", "All MCP read tools (get_*, list_*, search, find_*, docs_query)"),
|
|
446
|
+
("tool:write", "write", "All MCP write tools (create_*, update_*, add_*, set_*)"),
|
|
447
|
+
(
|
|
448
|
+
"tool:destructive",
|
|
449
|
+
"destructive",
|
|
450
|
+
"All MCP destructive tools (delete_*, remove_*)",
|
|
451
|
+
),
|
|
452
|
+
]
|
|
453
|
+
for name, category, description in mcp_categories:
|
|
454
|
+
# Check a representative tool for status
|
|
455
|
+
representative = "tool:get_buckets" if category == "read" else "tool:create_config"
|
|
456
|
+
if category == "destructive":
|
|
457
|
+
representative = "tool:delete_config"
|
|
458
|
+
status = "allowed" if self.is_allowed(representative) else "denied"
|
|
459
|
+
ops.append(
|
|
460
|
+
{
|
|
461
|
+
"name": name,
|
|
462
|
+
"type": "mcp",
|
|
463
|
+
"category": category,
|
|
464
|
+
"status": status,
|
|
465
|
+
"description": description,
|
|
466
|
+
}
|
|
467
|
+
)
|
|
468
|
+
|
|
469
|
+
return ops
|