graph-agents-cli 0.3.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.
- graph_agents_cli/__init__.py +26 -0
- graph_agents_cli/_api_policy.py +2145 -0
- graph_agents_cli/_approvals.py +400 -0
- graph_agents_cli/_build.py +186 -0
- graph_agents_cli/_build_info.json +7 -0
- graph_agents_cli/_chat_client.py +462 -0
- graph_agents_cli/_click.py +157 -0
- graph_agents_cli/_defaults.py +139 -0
- graph_agents_cli/_experiments.py +64 -0
- graph_agents_cli/_http.py +192 -0
- graph_agents_cli/_output.py +83 -0
- graph_agents_cli/_project.py +462 -0
- graph_agents_cli/_remote.py +220 -0
- graph_agents_cli/_response_schema.py +264 -0
- graph_agents_cli/_runner.py +319 -0
- graph_agents_cli/_skills_check.py +274 -0
- graph_agents_cli/_tools.py +189 -0
- graph_agents_cli/_trust.py +66 -0
- graph_agents_cli/api/__init__.py +15 -0
- graph_agents_cli/api/_changes.py +506 -0
- graph_agents_cli/api/_files.py +658 -0
- graph_agents_cli/api/cmd_api.py +2480 -0
- graph_agents_cli/deploy/__init__.py +15 -0
- graph_agents_cli/deploy/_config.py +171 -0
- graph_agents_cli/deploy/_image.py +128 -0
- graph_agents_cli/deploy/_kube.py +286 -0
- graph_agents_cli/deploy/_modes.py +234 -0
- graph_agents_cli/deploy/_preflight.py +370 -0
- graph_agents_cli/deploy/_values.py +168 -0
- graph_agents_cli/deploy/cmd_deploy.py +1866 -0
- graph_agents_cli/deploy/gitops.py +562 -0
- graph_agents_cli/deploy/local_load.py +273 -0
- graph_agents_cli/dev/__init__.py +13 -0
- graph_agents_cli/dev/cmd_build.py +131 -0
- graph_agents_cli/dev/cmd_install.py +78 -0
- graph_agents_cli/dev/cmd_lint.py +119 -0
- graph_agents_cli/dev/cmd_playground.py +297 -0
- graph_agents_cli/dev/policy_check.py +1287 -0
- graph_agents_cli/eval/__init__.py +22 -0
- graph_agents_cli/eval/_client.py +670 -0
- graph_agents_cli/eval/_common.py +177 -0
- graph_agents_cli/eval/_judge.py +168 -0
- graph_agents_cli/eval/_judge_runner.py +238 -0
- graph_agents_cli/eval/_paths.py +212 -0
- graph_agents_cli/eval/checks.py +581 -0
- graph_agents_cli/eval/cmd_analyze.py +278 -0
- graph_agents_cli/eval/cmd_compare.py +284 -0
- graph_agents_cli/eval/cmd_eval_group.py +80 -0
- graph_agents_cli/eval/cmd_generate.py +558 -0
- graph_agents_cli/eval/cmd_grade.py +466 -0
- graph_agents_cli/eval/cmd_metric.py +156 -0
- graph_agents_cli/eval/cmd_run.py +370 -0
- graph_agents_cli/eval/cmd_submit.py +400 -0
- graph_agents_cli/eval/config.py +435 -0
- graph_agents_cli/eval/dataset.py +350 -0
- graph_agents_cli/eval/gate.py +420 -0
- graph_agents_cli/eval/transcript.py +192 -0
- graph_agents_cli/extension/__init__.py +13 -0
- graph_agents_cli/extension/_compat.py +86 -0
- graph_agents_cli/extension/_loader.py +293 -0
- graph_agents_cli/extension/_manifest.py +135 -0
- graph_agents_cli/extension/_overrides.py +195 -0
- graph_agents_cli/extension/_paths.py +91 -0
- graph_agents_cli/extension/_refs.py +193 -0
- graph_agents_cli/extension/_resolver.py +453 -0
- graph_agents_cli/extension/_schema.py +106 -0
- graph_agents_cli/extension/_spec.py +253 -0
- graph_agents_cli/extension/_sync.py +102 -0
- graph_agents_cli/extension/_trust.py +58 -0
- graph_agents_cli/extension/cmd_extension_add.py +259 -0
- graph_agents_cli/extension/cmd_extension_group.py +57 -0
- graph_agents_cli/extension/cmd_extension_list.py +56 -0
- graph_agents_cli/extension/cmd_extension_remove.py +61 -0
- graph_agents_cli/extension/cmd_extension_update.py +195 -0
- graph_agents_cli/info/__init__.py +13 -0
- graph_agents_cli/info/cmd_info.py +222 -0
- graph_agents_cli/infra/__init__.py +15 -0
- graph_agents_cli/infra/checks.py +1169 -0
- graph_agents_cli/infra/cmd_infra.py +103 -0
- graph_agents_cli/main.py +591 -0
- graph_agents_cli/peer/__init__.py +15 -0
- graph_agents_cli/peer/_generate.py +254 -0
- graph_agents_cli/peer/cmd_peer.py +1151 -0
- graph_agents_cli/run/__init__.py +13 -0
- graph_agents_cli/run/_local_server.py +1157 -0
- graph_agents_cli/run/_signals.py +141 -0
- graph_agents_cli/run/cmd_approvals.py +530 -0
- graph_agents_cli/run/cmd_run.py +1421 -0
- graph_agents_cli/scaffold/__init__.py +19 -0
- graph_agents_cli/scaffold/agents/README.md +24 -0
- graph_agents_cli/scaffold/agents/empty_py/.template/templateconfig.yaml +22 -0
- graph_agents_cli/scaffold/agents/langgraph/.env.example +292 -0
- graph_agents_cli/scaffold/agents/langgraph/.template/templateconfig.yaml +28 -0
- graph_agents_cli/scaffold/agents/langgraph/Dockerfile +59 -0
- graph_agents_cli/scaffold/agents/langgraph/Dockerfile.langgraph-server +59 -0
- graph_agents_cli/scaffold/agents/langgraph/README.md +571 -0
- graph_agents_cli/scaffold/agents/langgraph/api-policy.yaml +60 -0
- graph_agents_cli/scaffold/agents/langgraph/app/__init__.py +20 -0
- graph_agents_cli/scaffold/agents/langgraph/app/agent.py +174 -0
- graph_agents_cli/scaffold/agents/langgraph/app/app_utils/__init__.py +15 -0
- graph_agents_cli/scaffold/agents/langgraph/app/app_utils/a2a.py +2162 -0
- graph_agents_cli/scaffold/agents/langgraph/app/app_utils/a2a_client.py +1167 -0
- graph_agents_cli/scaffold/agents/langgraph/app/app_utils/api_client.py +4220 -0
- graph_agents_cli/scaffold/agents/langgraph/app/app_utils/approvals.py +1349 -0
- graph_agents_cli/scaffold/agents/langgraph/app/app_utils/auth.py +1986 -0
- graph_agents_cli/scaffold/agents/langgraph/app/app_utils/chat.py +2962 -0
- graph_agents_cli/scaffold/agents/langgraph/app/app_utils/checkpointer.py +432 -0
- graph_agents_cli/scaffold/agents/langgraph/app/app_utils/content.py +569 -0
- graph_agents_cli/scaffold/agents/langgraph/app/app_utils/db.py +580 -0
- graph_agents_cli/scaffold/agents/langgraph/app/app_utils/limits.py +203 -0
- graph_agents_cli/scaffold/agents/langgraph/app/app_utils/metrics.py +231 -0
- graph_agents_cli/scaffold/agents/langgraph/app/app_utils/middleware.py +361 -0
- graph_agents_cli/scaffold/agents/langgraph/app/app_utils/model.py +611 -0
- graph_agents_cli/scaffold/agents/langgraph/app/app_utils/playground.py +230 -0
- graph_agents_cli/scaffold/agents/langgraph/app/app_utils/run_locks.py +459 -0
- graph_agents_cli/scaffold/agents/langgraph/app/app_utils/structured.py +755 -0
- graph_agents_cli/scaffold/agents/langgraph/app/app_utils/telemetry.py +681 -0
- graph_agents_cli/scaffold/agents/langgraph/app/app_utils/threads.py +493 -0
- graph_agents_cli/scaffold/agents/langgraph/app/app_utils/token_exchange.py +959 -0
- graph_agents_cli/scaffold/agents/langgraph/app/fast_api_app.py +770 -0
- graph_agents_cli/scaffold/agents/langgraph/app/policies/__init__.py +55 -0
- graph_agents_cli/scaffold/agents/langgraph/app/policies/custom.py +97 -0
- graph_agents_cli/scaffold/agents/langgraph/app/tools/__init__.py +46 -0
- graph_agents_cli/scaffold/agents/langgraph/app/tools/example_api.py +92 -0
- graph_agents_cli/scaffold/agents/langgraph/app/tools/weather.py +33 -0
- graph_agents_cli/scaffold/agents/langgraph/langgraph.json +14 -0
- graph_agents_cli/scaffold/agents/langgraph/pyproject.toml +78 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/conftest.py +376 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/eval/datasets/basic-dataset.json +53 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/eval/eval_config.yaml +32 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/integration/approval_graph.py +137 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/integration/fake_issuer.py +216 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/integration/fake_openai.py +357 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/integration/test_a2a_outcomes.py +569 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/integration/test_a2a_relay.py +479 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/integration/test_api_surface.py +812 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/integration/test_approvals.py +1367 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/integration/test_approvals_server.py +794 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/integration/test_cross_actor.py +497 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/integration/test_cross_actor_server.py +247 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/integration/test_history_repair.py +278 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/integration/test_model_apis.py +242 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/integration/test_postgres.py +637 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/integration/test_resilience_postgres.py +770 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/integration/test_runtime_guardrails.py +854 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/integration/test_server_e2e.py +340 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/integration/test_server_runtime.py +989 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/integration/test_structured_answers.py +584 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/integration/test_structured_server.py +222 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/integration/test_token_exchange_issuer.py +650 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/load_test/.results/.placeholder +0 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/load_test/README.md +22 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/load_test/conftest.py +21 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/load_test/load_test.py +81 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/unit/test_a2a_client.py +824 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/unit/test_a2a_scoping.py +724 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/unit/test_api_client.py +1214 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/unit/test_api_client_hardening.py +716 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/unit/test_api_policy_rpc.py +767 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/unit/test_approval_ledger.py +1536 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/unit/test_fake_model.py +115 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/unit/test_jwt_policy.py +991 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/unit/test_limits.py +310 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/unit/test_logging.py +148 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/unit/test_logging_hardening.py +271 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/unit/test_policy.py +378 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/unit/test_resilience.py +610 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/unit/test_server_auth.py +702 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/unit/test_structured.py +673 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/unit/test_telemetry.py +404 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/unit/test_thread_listing.py +255 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/unit/test_threads.py +268 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/unit/test_token_exchange.py +1320 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/unit/test_untrusted_content.py +393 -0
- graph_agents_cli/scaffold/agents/langgraph/uv-fastapi.lock +2084 -0
- graph_agents_cli/scaffold/agents/langgraph/uv-langgraph-server.lock +2106 -0
- graph_agents_cli/scaffold/agents/langgraph/{{cookiecutter.agent_guidance_filename}} +129 -0
- graph_agents_cli/scaffold/base_templates/_shared/graph-agents-cli-manifest.yaml +36 -0
- graph_agents_cli/scaffold/base_templates/python/.dockerignore +32 -0
- graph_agents_cli/scaffold/base_templates/python/.github/CODEOWNERS +30 -0
- graph_agents_cli/scaffold/base_templates/python/.github/agent.env +7 -0
- graph_agents_cli/scaffold/base_templates/python/.github/workflows/pr_checks.yaml +214 -0
- graph_agents_cli/scaffold/base_templates/python/.gitignore +209 -0
- graph_agents_cli/scaffold/base_templates/python/tests/unit/test_dummy.py +23 -0
- graph_agents_cli/scaffold/base_templates/python/{{cookiecutter.agent_guidance_filename}} +35 -0
- graph_agents_cli/scaffold/cmd_scaffold_group.py +49 -0
- graph_agents_cli/scaffold/commands/__init__.py +13 -0
- graph_agents_cli/scaffold/commands/create.py +1424 -0
- graph_agents_cli/scaffold/commands/enhance.py +1652 -0
- graph_agents_cli/scaffold/commands/upgrade.py +570 -0
- graph_agents_cli/scaffold/deployment_targets/kubernetes/python/.github/agent.env +12 -0
- graph_agents_cli/scaffold/deployment_targets/kubernetes/python/.github/workflows/promote-to-prod.yaml +371 -0
- graph_agents_cli/scaffold/deployment_targets/kubernetes/python/.github/workflows/staging.yaml +450 -0
- graph_agents_cli/scaffold/deployment_targets/kubernetes/python/deployment/argocd/application-dev.yaml +43 -0
- graph_agents_cli/scaffold/deployment_targets/kubernetes/python/deployment/argocd/application-prod.yaml +41 -0
- graph_agents_cli/scaffold/deployment_targets/kubernetes/python/deployment/argocd/application-staging.yaml +43 -0
- graph_agents_cli/scaffold/deployment_targets/kubernetes/python/deployment/helm/{{cookiecutter.project_name}}/.helmignore +14 -0
- graph_agents_cli/scaffold/deployment_targets/kubernetes/python/deployment/helm/{{cookiecutter.project_name}}/Chart.yaml +21 -0
- graph_agents_cli/scaffold/deployment_targets/kubernetes/python/deployment/helm/{{cookiecutter.project_name}}/examples/networkpolicy.yaml +103 -0
- graph_agents_cli/scaffold/deployment_targets/kubernetes/python/deployment/helm/{{cookiecutter.project_name}}/templates/NOTES.txt +48 -0
- graph_agents_cli/scaffold/deployment_targets/kubernetes/python/deployment/helm/{{cookiecutter.project_name}}/templates/_helpers.tpl +189 -0
- graph_agents_cli/scaffold/deployment_targets/kubernetes/python/deployment/helm/{{cookiecutter.project_name}}/templates/certificate.yaml +15 -0
- graph_agents_cli/scaffold/deployment_targets/kubernetes/python/deployment/helm/{{cookiecutter.project_name}}/templates/configmap.yaml +10 -0
- graph_agents_cli/scaffold/deployment_targets/kubernetes/python/deployment/helm/{{cookiecutter.project_name}}/templates/deployment.yaml +199 -0
- graph_agents_cli/scaffold/deployment_targets/kubernetes/python/deployment/helm/{{cookiecutter.project_name}}/templates/hpa.yaml +22 -0
- graph_agents_cli/scaffold/deployment_targets/kubernetes/python/deployment/helm/{{cookiecutter.project_name}}/templates/httproute.yaml +30 -0
- graph_agents_cli/scaffold/deployment_targets/kubernetes/python/deployment/helm/{{cookiecutter.project_name}}/templates/ingress.yaml +39 -0
- graph_agents_cli/scaffold/deployment_targets/kubernetes/python/deployment/helm/{{cookiecutter.project_name}}/templates/networkpolicy.yaml +48 -0
- graph_agents_cli/scaffold/deployment_targets/kubernetes/python/deployment/helm/{{cookiecutter.project_name}}/templates/pdb.yaml +13 -0
- graph_agents_cli/scaffold/deployment_targets/kubernetes/python/deployment/helm/{{cookiecutter.project_name}}/templates/postgresql-secret.yaml +37 -0
- graph_agents_cli/scaffold/deployment_targets/kubernetes/python/deployment/helm/{{cookiecutter.project_name}}/templates/service.yaml +15 -0
- graph_agents_cli/scaffold/deployment_targets/kubernetes/python/deployment/helm/{{cookiecutter.project_name}}/templates/serviceaccount.yaml +13 -0
- graph_agents_cli/scaffold/deployment_targets/kubernetes/python/deployment/helm/{{cookiecutter.project_name}}/templates/servicemonitor.yaml +42 -0
- graph_agents_cli/scaffold/deployment_targets/kubernetes/python/deployment/helm/{{cookiecutter.project_name}}/values-dev.yaml +22 -0
- graph_agents_cli/scaffold/deployment_targets/kubernetes/python/deployment/helm/{{cookiecutter.project_name}}/values-prod.yaml +45 -0
- graph_agents_cli/scaffold/deployment_targets/kubernetes/python/deployment/helm/{{cookiecutter.project_name}}/values-staging.yaml +29 -0
- graph_agents_cli/scaffold/deployment_targets/kubernetes/python/deployment/helm/{{cookiecutter.project_name}}/values.yaml +396 -0
- graph_agents_cli/scaffold/deployment_targets/kubernetes/python/tests/integration/test_chart.py +269 -0
- graph_agents_cli/scaffold/deployment_targets/none/README.md +5 -0
- graph_agents_cli/scaffold/deployment_targets/none/python/README.md +6 -0
- graph_agents_cli/scaffold/utils/__init__.py +13 -0
- graph_agents_cli/scaffold/utils/backup.py +212 -0
- graph_agents_cli/scaffold/utils/build_record.py +257 -0
- graph_agents_cli/scaffold/utils/cli_options.py +184 -0
- graph_agents_cli/scaffold/utils/fs.py +83 -0
- graph_agents_cli/scaffold/utils/generate_locks.py +214 -0
- graph_agents_cli/scaffold/utils/generation_metadata.py +88 -0
- graph_agents_cli/scaffold/utils/keyedit.py +768 -0
- graph_agents_cli/scaffold/utils/keymerge.py +537 -0
- graph_agents_cli/scaffold/utils/language.py +138 -0
- graph_agents_cli/scaffold/utils/lock_utils.py +94 -0
- graph_agents_cli/scaffold/utils/logging.py +77 -0
- graph_agents_cli/scaffold/utils/manifest.py +292 -0
- graph_agents_cli/scaffold/utils/merge.py +970 -0
- graph_agents_cli/scaffold/utils/merge3.py +216 -0
- graph_agents_cli/scaffold/utils/openapi_seed.py +199 -0
- graph_agents_cli/scaffold/utils/remote_template.py +376 -0
- graph_agents_cli/scaffold/utils/template.py +1352 -0
- graph_agents_cli/scaffold/utils/upgrade.py +894 -0
- graph_agents_cli/scaffold/utils/version.py +438 -0
- graph_agents_cli/secrets/__init__.py +15 -0
- graph_agents_cli/secrets/_apply.py +954 -0
- graph_agents_cli/secrets/_required.py +188 -0
- graph_agents_cli/secrets/cmd_secrets.py +211 -0
- graph_agents_cli/setup/__init__.py +13 -0
- graph_agents_cli/setup/_antigravity.py +221 -0
- graph_agents_cli/setup/cmd_auth.py +1030 -0
- graph_agents_cli/setup/cmd_dev_token.py +513 -0
- graph_agents_cli/setup/cmd_setup.py +428 -0
- graph_agents_cli/setup/cmd_update.py +140 -0
- graph_agents_cli/skills/__init__.py +13 -0
- graph_agents_cli/skills/_bundle.py +65 -0
- graph_agents_cli/skills/data/README.md +19 -0
- graph_agents_cli/skills/data/graph-agents-cli-deploy/SKILL.md +357 -0
- graph_agents_cli/skills/data/graph-agents-cli-deploy/references/github-settings.md +113 -0
- graph_agents_cli/skills/data/graph-agents-cli-deploy/references/gitops.md +137 -0
- graph_agents_cli/skills/data/graph-agents-cli-deploy/references/kubernetes.md +315 -0
- graph_agents_cli/skills/data/graph-agents-cli-deploy/references/secrets.md +160 -0
- graph_agents_cli/skills/data/graph-agents-cli-eval/SKILL.md +303 -0
- graph_agents_cli/skills/data/graph-agents-cli-eval/references/dataset_schema.md +282 -0
- graph_agents_cli/skills/data/graph-agents-cli-eval/references/metrics-guide.md +143 -0
- graph_agents_cli/skills/data/graph-agents-cli-langgraph-code/SKILL.md +659 -0
- graph_agents_cli/skills/data/graph-agents-cli-langgraph-code/references/langchain-models.md +124 -0
- graph_agents_cli/skills/data/graph-agents-cli-langgraph-code/references/langgraph.md +235 -0
- graph_agents_cli/skills/data/graph-agents-cli-langgraph-code/references/template-contract.md +477 -0
- graph_agents_cli/skills/data/graph-agents-cli-observability/SKILL.md +231 -0
- graph_agents_cli/skills/data/graph-agents-cli-observability/references/langsmith.md +46 -0
- graph_agents_cli/skills/data/graph-agents-cli-observability/references/otel.md +59 -0
- graph_agents_cli/skills/data/graph-agents-cli-scaffold/SKILL.md +414 -0
- graph_agents_cli/skills/data/graph-agents-cli-scaffold/references/flags.md +134 -0
- graph_agents_cli/skills/data/graph-agents-cli-workflow/SKILL.md +478 -0
- graph_agents_cli/skills/data/graph-agents-cli-workflow/references/brainstorming.md +118 -0
- graph_agents_cli/skills/data/graph-agents-cli-workflow/references/commands.md +419 -0
- graph_agents_cli/skills/data/graph-agents-cli-workflow/references/extension.md +156 -0
- graph_agents_cli/skills/data/graph-agents-cli-workflow/references/internals.md +67 -0
- graph_agents_cli/skills/data/graph-agents-cli-workflow/references/spec-template.md +56 -0
- graph_agents_cli/skills/data/graph-agents-cli-workflow/references/terminology.md +119 -0
- graph_agents_cli/system/__init__.py +15 -0
- graph_agents_cli/system/_apply.py +519 -0
- graph_agents_cli/system/_checks.py +1023 -0
- graph_agents_cli/system/_deploy.py +215 -0
- graph_agents_cli/system/_model.py +363 -0
- graph_agents_cli/system/_system.py +664 -0
- graph_agents_cli/system/_views.py +208 -0
- graph_agents_cli/system/cmd_system.py +423 -0
- graph_agents_cli-0.3.1.dist-info/METADATA +162 -0
- graph_agents_cli-0.3.1.dist-info/RECORD +291 -0
- graph_agents_cli-0.3.1.dist-info/WHEEL +4 -0
- graph_agents_cli-0.3.1.dist-info/entry_points.txt +2 -0
- graph_agents_cli-0.3.1.dist-info/licenses/LICENSE +201 -0
- graph_agents_cli-0.3.1.dist-info/licenses/NOTICE +19 -0
|
@@ -0,0 +1,357 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: graph-agents-cli-deploy
|
|
3
|
+
description: >
|
|
4
|
+
This skill should be used when the user wants to "deploy an agent",
|
|
5
|
+
"deploy to Kubernetes", "deploy to our cluster", "set up CI/CD", "set up
|
|
6
|
+
Argo CD", "configure secrets", "rotate a key", "promote to production",
|
|
7
|
+
"check cluster prerequisites", "deploy to kind/k3s/minikube", "deploy
|
|
8
|
+
air-gapped", or "troubleshoot a deployment". Covers the deployment modes
|
|
9
|
+
(direct local-load, direct registry, helm-push, argocd), the dev/staging/
|
|
10
|
+
prod environments, the secrets procedure and rotation, the Argo CD PR
|
|
11
|
+
flow and the single production merge gate, the required GitHub
|
|
12
|
+
environment and branch-protection settings, `infra check`, local-load dev
|
|
13
|
+
clusters, and the disconnected profile. Part of the graph-agents-cli
|
|
14
|
+
skills suite. Do NOT use for agent code (graph-agents-cli-langgraph-code),
|
|
15
|
+
evaluation (graph-agents-cli-eval), scaffolding
|
|
16
|
+
(graph-agents-cli-scaffold), or tracing (graph-agents-cli-observability).
|
|
17
|
+
metadata:
|
|
18
|
+
author: graph-agents-cli contributors
|
|
19
|
+
license: Apache-2.0
|
|
20
|
+
version: "0.3.1"
|
|
21
|
+
requires:
|
|
22
|
+
bins:
|
|
23
|
+
- graph-agents-cli
|
|
24
|
+
install: "uv tool install git+https://github.com/ss7172/graph-agents-cli@v0.3.1"
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
# Deployment guide
|
|
28
|
+
|
|
29
|
+
> **Requires:** `graph-agents-cli`, plus `docker`, `helm`, `kubectl`, `git`, a kubeconfig, `gh` for
|
|
30
|
+
> GitHub-hosted CD, and `argocd` when `cd: argocd`. The CLI shells out to these; it never installs cluster components. If the
|
|
31
|
+
> project has no deployment target, `/graph-agents-cli-scaffold` adds one with `scaffold enhance`.
|
|
32
|
+
|
|
33
|
+
> **Never deploy without explicit human approval.** In `argocd` mode you open a PR; a code owner
|
|
34
|
+
> merges it. You never merge it.
|
|
35
|
+
|
|
36
|
+
## Reference files
|
|
37
|
+
|
|
38
|
+
| File | Contents |
|
|
39
|
+
|---|---|
|
|
40
|
+
| `references/kubernetes.md` | Helm chart values and render-time refusals, pod security, probes, published routes (`route.publicPaths`), traffic entry (Gateway API / Ingress / TLS), metrics and NetworkPolicy, Postgres and Redis toggles, HPA/PDB, local-load dev clusters, rollback, disconnected profile |
|
|
41
|
+
| `references/gitops.md` | The argocd mode: `Application` manifests, the `deploy` PR flow, staging auto-merge, production promotion, rollback by revert, `--restart` under self-heal |
|
|
42
|
+
| `references/secrets.md` | The Secret contract, allow-listed and required keys, env-file and context rules, `secrets apply/status` (server-side apply, key merge, `API_KEY` handling), ownership in CD modes, rotation |
|
|
43
|
+
| `references/github-settings.md` | Required GitHub environment and branch-protection settings, `CODEOWNERS`, secrets and variables (`DEPLOY_KUBECONFIG`, `GH_PR_TOKEN`), the self-hosted runner, what `infra check` reports |
|
|
44
|
+
|
|
45
|
+
---
|
|
46
|
+
|
|
47
|
+
## Deployment modes (determined by the manifest's `cd` and the environment)
|
|
48
|
+
|
|
49
|
+
| Mode | Who applies the release | What `deploy` does |
|
|
50
|
+
|---|---|---|
|
|
51
|
+
| *direct, local-load* (`cd: skip`, local cluster) | `deploy` | builds the image with the `docker` CLI, loads it into the kind/k3d/k3s/minikube node (nothing for Docker Desktop, Rancher Desktop, OrbStack), applies the Secret from the allow-listed keys of the env file, runs `helm upgrade --install --wait` |
|
|
52
|
+
| *direct, registry* (`cd: skip`, any other cluster) | `deploy` | builds, pushes to the manifest's registry, applies the Secret, runs `helm upgrade --install --wait` |
|
|
53
|
+
| *helm-push* (`cd: helm-push`) | GitHub Actions on a self-hosted runner | CI builds and pushes; the runner job runs `deploy --env <env> --image <ref> --context <ctx> --yes`, which only runs helm (after checking the live Secret's required keys). From a workstation `dev` is allowed; `staging`/`prod` are refused outside CI (`GITHUB_ACTIONS=true`) **even with `--image`**, unless `--force-direct` |
|
|
54
|
+
| *argocd* (`cd: argocd`) | Argo CD inside the cluster | **`deploy` never runs helm, never contacts the cluster and never merges.** `deploy --env <env> --image <ref>` writes the desired state: it updates `image.tag` in `deployment/helm/<name>/values-<env>.yaml` (and nothing else), commits on a branch `deploy/<env>/<short sha>` built with git plumbing from `origin/main` (the developer's checkout is never switched), and opens or updates a pull request with `gh` (else GitHub REST with `GITHUB_TOKEN`; `GH_HOST=<host>` for a GitHub Enterprise Server). `--image` names the CI-pushed image; without it the tag is `--tag` or the short git sha with a warning. Argo reconciles from `main`, so nothing reaches the cluster until the PR merges, and a PR touching `values-prod.yaml` merges only after the production approval, whoever opened it. In argocd environments only `--status`, `--restart`, and `secrets` touch the cluster |
|
|
55
|
+
|
|
56
|
+
Local-load is decided from the cluster itself (its nodes), confirmed with `kind get clusters`,
|
|
57
|
+
`k3d cluster list` or `minikube profile list`; the context name decides only when the nodes
|
|
58
|
+
cannot be read. `deploy --dry-run` prints the docker, helm, kubectl, and gh commands plus the
|
|
59
|
+
rendered manifests, changes nothing and never prompts. It runs the same checks as the real run,
|
|
60
|
+
including a read-only read of the live Secret, so it refuses (exit 1) a deploy the real run
|
|
61
|
+
would refuse for a missing required key (and says so when the cluster cannot be read).
|
|
62
|
+
`helm dependency build deployment/helm/<name>` is printed with the `[dry-run]` prefix and still
|
|
63
|
+
executed when a declared subchart is missing from `charts/`, because it only writes into the
|
|
64
|
+
chart directory and the `helm template` render needs the subcharts. Use `--dry-run` to show the
|
|
65
|
+
user what will happen.
|
|
66
|
+
|
|
67
|
+
Images are tagged with the **short commit SHA**: `${GITHUB_SHA::7}` in the `staging` workflow,
|
|
68
|
+
`git rev-parse --short HEAD` for a workstation `deploy`, plus `-dirty-<YYYYmmddHHMMSS>` (with a
|
|
69
|
+
warning) when the tree has uncommitted changes outside `deployment/`, `.github/`, `tests/` and
|
|
70
|
+
`docs/`; a UTC timestamp outside git; `--tag TAG` overrides. The argocd branch is
|
|
71
|
+
`deploy/<env>/<short sha>` and the `promote-to-prod` `image_tag` input is a short sha. A
|
|
72
|
+
placeholder registry (`ghcr.io/CHANGE-ME`) or an invalid image reference is exit 3 before
|
|
73
|
+
`docker` runs. The chart refuses an empty `image.tag` and an unquoted numeric one.
|
|
74
|
+
|
|
75
|
+
Exit codes: `0` ok; `1` refused (policy or mode, a declined or missing context confirmation, a
|
|
76
|
+
Secret missing a required key, `--status` on a rollout that is not complete within `--timeout`);
|
|
77
|
+
`2` tool failure (helm/kubectl/docker non-zero or missing from `PATH`, a failed rollout, a
|
|
78
|
+
`--restart` whose new pods do not become ready, another helm operation holding the release,
|
|
79
|
+
`helm dependency build` failing because `registry-1.docker.io` is unreachable); `3`
|
|
80
|
+
configuration error (no env file outside dev, an unknown context, a placeholder registry, a
|
|
81
|
+
`CHANGE-ME` left in the chart `env` outside dev, `jwt` without a verification key, issuer or
|
|
82
|
+
audience outside dev, a blank `gateway.parentRef.name`).
|
|
83
|
+
|
|
84
|
+
## Environments
|
|
85
|
+
|
|
86
|
+
`dev`, `staging`, `prod`. Each has a values file `deployment/helm/<name>/values-<env>.yaml`, a
|
|
87
|
+
namespace `<name>-<env>` (recorded with its kube context under `environments:` in the manifest),
|
|
88
|
+
a Secret `<name>-app`, and under argocd an `Application`. `dev` may be a local-load cluster.
|
|
89
|
+
|
|
90
|
+
| Values file | Defaults |
|
|
91
|
+
|---|---|
|
|
92
|
+
| `values-dev.yaml` | `env.APP_ENV=dev`, `secretOptional: true`, `postgresql.enabled=true` (bundled subchart; Redis too under `langgraph-server`), `gateway.enabled=false` |
|
|
93
|
+
| `values-staging.yaml` | `secretOptional: false` (pods need the Secret), `postgresql.enabled=false` (external DSN from the Secret), gateway on, hostnames blank for the operator to fill |
|
|
94
|
+
| `values-prod.yaml` | as staging, plus `replicaCount: 2`, a PDB, topology spread and larger requests |
|
|
95
|
+
|
|
96
|
+
## Rules `deploy` and `secrets apply` follow
|
|
97
|
+
|
|
98
|
+
- **Env file:** `--env-file`, else `.env.<env>`. Only `dev` falls back to `.env`; any other
|
|
99
|
+
environment without one exits 3 (local development keys never reach staging or prod).
|
|
100
|
+
- **Kube context:** `--context`, else `environments.<env>.context`, else the kubeconfig's current
|
|
101
|
+
context. Outside `dev` the current context needs a confirmation (a prompt at a terminal,
|
|
102
|
+
`--yes` otherwise; exit 1 without). An explicit context missing from the kubeconfig is exit 3.
|
|
103
|
+
The resolved context and API server are printed before anything happens. Prefer recording the
|
|
104
|
+
context in the manifest for staging and prod.
|
|
105
|
+
- **Order (direct mode):** project checks (chart, values, image reference, env file, chart `env`
|
|
106
|
+
placeholders, `jwt` settings the chart lists); the context; a read-only check that the Secret
|
|
107
|
+
the deploy would produce holds every required key (exit 1 before anything is built) and that
|
|
108
|
+
`jwt` can verify tokens with it; a refusal (exit 2) while another helm operation holds the
|
|
109
|
+
release, with the command that clears a lock left by an interrupted helm; then build, load or
|
|
110
|
+
push, the namespace (created when missing), the Secret, and `helm upgrade --install --wait
|
|
111
|
+
--timeout <--timeout, default 5m>`.
|
|
112
|
+
- **Chart env placeholders:** a `CHANGE-ME` left in the merged chart `env` (an API base URL from
|
|
113
|
+
`api add`, `OPENAI_BASE_URL` of an `openai-compatible` project) is refused outside dev in every
|
|
114
|
+
mode (exit 3, naming the key and the values file) and a warning in dev.
|
|
115
|
+
- **`jwt` settings:** outside dev (or when `APP_ENV` is not `dev`) the chart env or the Secret
|
|
116
|
+
must provide a verification key (`AUTH_JWT_JWKS_URL` or `AUTH_JWT_PUBLIC_KEY`), the issuer and
|
|
117
|
+
the audience, or `deploy` exits 3 (the pods would refuse to start). A setting the chart env
|
|
118
|
+
lists, even empty, overrides the Secret. In dev a missing key source is a warning (the pods
|
|
119
|
+
start and answer 503).
|
|
120
|
+
- **Failed rollout:** the pods' states, this release's warning events since the deploy started
|
|
121
|
+
and the logs are printed, then with `--atomic` (default) the release is rolled back to the
|
|
122
|
+
newest good revision, or a first install that never succeeded is uninstalled. Only the
|
|
123
|
+
revision this run created is ever undone. Once the release is back where it was, the app
|
|
124
|
+
Secret (and `<name>-metrics`) this deploy applied is restored to its previous values, or
|
|
125
|
+
deleted if this deploy created it, unless someone changed it since. `--no-atomic` leaves the
|
|
126
|
+
failed revision and the new Secret values in place and says so.
|
|
127
|
+
- **Same image:** when the release already runs the image being deployed, `deploy` says so up
|
|
128
|
+
front; after the upgrade it reports when no pod was replaced and, if the Secret changed, that
|
|
129
|
+
`deploy --restart` is what makes the pods read it.
|
|
130
|
+
- **Protected environments:** `deploy --env staging|prod` refuses while the manifest says
|
|
131
|
+
`auth_policy_implemented: false` (the `custom` stub).
|
|
132
|
+
|
|
133
|
+
## Standard procedure
|
|
134
|
+
|
|
135
|
+
1. **Gate:** `graph-agents-cli eval run` exits 0 and the user approved deploying.
|
|
136
|
+
2. **Prerequisites:** `graph-agents-cli infra check --env <env>`. Read-only; reports the required
|
|
137
|
+
tools and the kube context, Gateway API CRDs and classes (only when `gateway.enabled`) /
|
|
138
|
+
Ingress classes, cert-manager (only when `tls.certManager.enabled`), Argo CD (only when `cd:
|
|
139
|
+
argocd`), metrics-server (only when `hpa.enabled`), the namespace, the image pull secret, the
|
|
140
|
+
app Secret and its required keys, the `jwt` verification settings, the ServiceMonitor's token
|
|
141
|
+
Secret, whether an external DSN requires TLS, every `CHANGE-ME` placeholder (registry, chart
|
|
142
|
+
image and env, CODEOWNERS, Argo CD `repoURL`), where pending approvals are kept when
|
|
143
|
+
`api-policy.yaml` gates calls (the `approvals` table of the app database; a warning under
|
|
144
|
+
`CHECKPOINTER=memory`, which loses paused runs on a restart), and, when `gh` is logged in,
|
|
145
|
+
the environment protection, branch protection and (helm-push) `DEPLOY_KUBECONFIG` settings.
|
|
146
|
+
Nothing is created; install hints are printed for the operator, and every printed command
|
|
147
|
+
runs as is.
|
|
148
|
+
3. **Values:** fill `hostname`, `parentRef`, `tls`, `resources` in `values-<env>.yaml` and review
|
|
149
|
+
`route.publicPaths` (what the Gateway or Ingress publishes). For network isolation copy the
|
|
150
|
+
`networkPolicy` block of `deployment/helm/<name>/examples/networkpolicy.yaml` (DNS, the
|
|
151
|
+
database, the model endpoint, public HTTPS for hosted APIs) and set its addresses. For an
|
|
152
|
+
external database use a least-privileged role and `sslmode=verify-full` (see
|
|
153
|
+
`references/kubernetes.md`). These are config files: never
|
|
154
|
+
overwritten by upgrade, never containing secrets. `gateway.parentRef.name` is **required**
|
|
155
|
+
whenever `gateway.enabled` (the staging/prod default): `deploy` checks the merged values
|
|
156
|
+
before building or pushing anything and exits 3 naming the file when it is blank. Set
|
|
157
|
+
`appUrl` (or a hostname) so the A2A card advertises a reachable URL. Keep `image:` a nested
|
|
158
|
+
mapping (`image:` newline `tag: ...`), never an inline `{}` map, because `deploy` rewrites
|
|
159
|
+
`image.tag` textually. Record `environments.<env>.context` in the manifest.
|
|
160
|
+
4. **Secrets:** `graph-agents-cli secrets apply --env <env>` (from `.env.<env>`). CD modes: the
|
|
161
|
+
manifest's `secrets.owner` runs it from a workstation with cluster access; CI never holds
|
|
162
|
+
application secrets; Argo never manages the Secret. `secrets status --env <env>` lists keys
|
|
163
|
+
without values and exits 1 when a required key is missing. `deploy` refuses to touch Secrets
|
|
164
|
+
in `helm-push` and `argocd` modes and prints the procedure.
|
|
165
|
+
5. **Deploy:** `graph-agents-cli deploy --env <env>` (direct), or let CI run it (`helm-push`), or
|
|
166
|
+
open the PR (`argocd`).
|
|
167
|
+
6. **Verify:** `graph-agents-cli deploy --status --env <env>` (a bounded rollout status, 60 s by
|
|
168
|
+
default, with the image, helm revision and each pod's readiness and restarts; diagnostics and
|
|
169
|
+
exit 1 when not ready; `argocd app get` in argocd mode), then
|
|
170
|
+
`graph-agents-cli run --url https://<host> "hello"` with the environment's credential in
|
|
171
|
+
`GRAPH_AGENTS_CLI_API_KEY` (the environment's `API_KEY` under `shared-bearer`, a user's token
|
|
172
|
+
under `jwt`; kept out of argv and shell history), or `--header` / `--cookie` under `custom`.
|
|
173
|
+
Readiness is `/ready` (probed inside the cluster; not published on the route).
|
|
174
|
+
|
|
175
|
+
## Agents calling agents
|
|
176
|
+
|
|
177
|
+
- **One project:** `peer add` writes the peer's URL into each `values-<env>.yaml` from a
|
|
178
|
+
template with `{env}`:
|
|
179
|
+
`graph-agents-cli peer add orders --cluster-url 'http://orders-agent.orders-agent-{env}.svc.cluster.local'`.
|
|
180
|
+
- **Several projects:** `graph-agents-system.yaml` names them, the agents each calls, the
|
|
181
|
+
issuer and the environments. `graph-agents-cli system apply --dry-run`, then without it,
|
|
182
|
+
writes both sides of every edge per environment: the callers' peer URLs,
|
|
183
|
+
`TOKEN_EXCHANGE_URL` and `TOKEN_EXCHANGE_CLIENT_ID`; the called agents' `appUrl` (the URL
|
|
184
|
+
callers dial, which their card advertises: SC05), `AUTH_JWT_AUDIENCE` when empty and the
|
|
185
|
+
callers' actor ids in `AUTH_ALLOWED_ACTORS` (under `jwt` an agent not listed gets 403); and
|
|
186
|
+
NetworkPolicy `egressTo`/`ingressFrom` rules. It never writes gates, secrets or `.env`.
|
|
187
|
+
`graph-agents-cli system check --env <env>` (add `--live` after a deploy), then
|
|
188
|
+
`graph-agents-cli system deploy --env <env>` (the agents called first, `--parallel` at
|
|
189
|
+
once; outside dev every project records its kube context). Give the issuer's admin
|
|
190
|
+
`graph-agents-cli system delegations`: what each client may exchange for.
|
|
191
|
+
- **Callers** keep `TOKEN_EXCHANGE_CLIENT_SECRET` and `PRINCIPAL_HASH_SALT` in `secrets.keys`;
|
|
192
|
+
outside dev `deploy` refuses a peer credential over plain http (except loopback,
|
|
193
|
+
single-label and `.svc` hosts) and an exchange API without the issuer settings.
|
|
194
|
+
- **Keep A2A internal:** when only agents call an agent, drop `/a2a/<agent>` from
|
|
195
|
+
`route.publicPaths` (SC13) and turn on `networkPolicy`.
|
|
196
|
+
- **Sizing:** replicas share A2A tasks only on Postgres (more than one replica with in-memory
|
|
197
|
+
tasks is SC06). Agents sharing one database server open replicas x (`DB_POOL_MAX_SIZE` + 1)
|
|
198
|
+
connections each: set `database.max_connections` in the file (SC10), and above about 120
|
|
199
|
+
connections give agents their own databases or a session-mode PgBouncer.
|
|
200
|
+
|
|
201
|
+
## Secrets and rotation (summary)
|
|
202
|
+
|
|
203
|
+
- Only variables in the manifest's `secrets.keys` are exported: the provider key
|
|
204
|
+
(`OPENAI_API_KEY` | `ANTHROPIC_API_KEY` | `GOOGLE_API_KEY` | `MODEL_API_KEY`), `JUDGE_API_KEY`,
|
|
205
|
+
`POSTGRES_DSN` (fastapi) or `DATABASE_URI` + `REDIS_URI` (langgraph-server), `API_KEY`,
|
|
206
|
+
`LANGSMITH_API_KEY`, the `token_env` of every `auth: bearer` API in `api-policy.yaml`, and
|
|
207
|
+
`AUTH_JWT_SECRET` automatically under `jwt` with HS*. Never the whole env file. Add other
|
|
208
|
+
secrets (`METRICS_TOKEN`, `PRINCIPAL_HASH_SALT`) to the list.
|
|
209
|
+
- Server-side apply; allow-listed keys the env file leaves out are kept from the live Secret.
|
|
210
|
+
- `API_KEY`: the live key wins; it is replaced only when the env file sets another **and**
|
|
211
|
+
`--rotate-api-key` is passed. Under `shared-bearer` (the only policy that reads it), when
|
|
212
|
+
neither has one, a key is generated, applied and written to the env file (0600), never printed;
|
|
213
|
+
`jwt` and `custom` never get one generated. Values must be single-line.
|
|
214
|
+
- `METRICS_TOKEN` is also written alone into `<name>-metrics`, the Secret the ServiceMonitor
|
|
215
|
+
reads (Prometheus never needs the app Secret).
|
|
216
|
+
- **Rotation:** put the new value in `.env.<env>`, `secrets apply` (with `--rotate-api-key` for
|
|
217
|
+
`API_KEY`), then `deploy --restart --env <env>` (`kubectl rollout restart`, then it waits for
|
|
218
|
+
the new pods and prints diagnostics if they do not become ready), because an externally
|
|
219
|
+
managed Secret does not change the pod template. In argocd environments the restart is drift
|
|
220
|
+
that self-heal may revert; the warning suggests an Argo resource action instead.
|
|
221
|
+
- Details: `references/secrets.md`.
|
|
222
|
+
|
|
223
|
+
## argocd PR flow and the single production gate (summary)
|
|
224
|
+
|
|
225
|
+
- Staging: the `staging` workflow (on `main`) builds and pushes `<registry>/<name>:<short sha>`
|
|
226
|
+
(`${GITHUB_SHA::7}`), writes the tag into `values-staging.yaml` on `deploy/staging/<short sha>`
|
|
227
|
+
(built on the latest `main`, superseding older staging PRs) and opens a PR with auto-merge;
|
|
228
|
+
Argo syncs staging with self-heal. A PR opened with the workflow `GITHUB_TOKEN` never triggers
|
|
229
|
+
`pr_checks`, so auto-merge on that required check needs a fine-grained PAT or GitHub App token
|
|
230
|
+
(pull-request and contents write) in the `GH_PR_TOKEN` repository secret.
|
|
231
|
+
- Production: desired state changes **only** through a PR touching `values-prod.yaml`, opened by
|
|
232
|
+
the `promote-to-prod` workflow (running in the GitHub `production` environment) or by a
|
|
233
|
+
workstation `deploy --env prod --image <ref>`. Neither path merges. The merge requires review
|
|
234
|
+
from the code owners of `values-prod.yaml`, cannot be self-approved, and requires `pr_checks`
|
|
235
|
+
to pass. That merge is the single gate. Prod `Application` has no automated sync; an operator
|
|
236
|
+
syncs in Argo after the merge.
|
|
237
|
+
- Rollback is a git revert (a PR under the same gate). No inbound access from GitHub to the
|
|
238
|
+
cluster. Details: `references/gitops.md`.
|
|
239
|
+
|
|
240
|
+
## Required GitHub settings (summary)
|
|
241
|
+
|
|
242
|
+
Repository configuration a workflow cannot create for itself; the operator sets it, `infra
|
|
243
|
+
check` reports it, the scaffolded README documents it:
|
|
244
|
+
|
|
245
|
+
- Environment `production`: required reviewers (at least one), prevent self-review, deployment
|
|
246
|
+
branches restricted to `main`, optional wait timer. Environment `staging`: deployment branches
|
|
247
|
+
restricted to `main`.
|
|
248
|
+
- `helm-push`: the `DEPLOY_KUBECONFIG` secret in **each environment** (never a repository
|
|
249
|
+
secret), and a self-hosted runner with `kubectl` and `curl`.
|
|
250
|
+
- Branch protection on `main` (argocd and helm-push): pull requests required; code-owner review
|
|
251
|
+
required; dismiss stale approvals; prevent self-approval; `pr_checks` required; auto-merge
|
|
252
|
+
allowed.
|
|
253
|
+
- `.github/CODEOWNERS` owns `deployment/` (except the dev and staging values), `.github/`,
|
|
254
|
+
`api-policy.yaml`, `tests/eval/`, the extensions and the manifest; replace the
|
|
255
|
+
`@CHANGE-ME/production-approvers` placeholder.
|
|
256
|
+
- Repository secret `GH_PR_TOKEN` so the desired-state PRs opened by CI trigger `pr_checks`.
|
|
257
|
+
- Optional: the provider key secret (or `MODEL_PROVIDER` / `MODEL_NAME` variables) so the
|
|
258
|
+
`pr_checks` eval gate runs on a real model.
|
|
259
|
+
- GitHub Enterprise Server: set `GH_HOST=<host>` (plus `GH_ENTERPRISE_TOKEN` or `GITHUB_TOKEN`)
|
|
260
|
+
where `deploy` runs so argocd-mode PRs go to that host.
|
|
261
|
+
- Details: `references/github-settings.md`.
|
|
262
|
+
|
|
263
|
+
## Local-load dev clusters
|
|
264
|
+
|
|
265
|
+
With `cd: skip` and a local cluster (kind, k3d, k3s on this machine, minikube, Docker Desktop,
|
|
266
|
+
Rancher Desktop, OrbStack), `deploy --env dev` skips the registry: it builds with `docker build`,
|
|
267
|
+
loads the image into the node (`kind load docker-image`, `k3d image import`, `docker save` then
|
|
268
|
+
`k3s ctr images import`, `minikube image load`; nothing for the shared-daemon clusters), applies
|
|
269
|
+
the Secret, runs `helm dependency build` when the subcharts are missing, and runs helm with
|
|
270
|
+
`values-dev.yaml` (bundled Postgres, and Redis under `langgraph-server`, gateway off,
|
|
271
|
+
`APP_ENV=dev` so `/playground` is served). The k3s import runs without `sudo` and needs root on
|
|
272
|
+
most k3s hosts. Reach it with `kubectl -n <name>-dev port-forward svc/<name> 8000:80`. Only the
|
|
273
|
+
`docker` CLI is supported for builds.
|
|
274
|
+
|
|
275
|
+
## Disconnected profile
|
|
276
|
+
|
|
277
|
+
The one configuration in which the whole lifecycle runs without internet access:
|
|
278
|
+
|
|
279
|
+
| Component | Requirement |
|
|
280
|
+
|---|---|
|
|
281
|
+
| Agent model | `MODEL_PROVIDER=openai-compatible`, `OPENAI_BASE_URL` at an in-cluster or on-network server (vLLM, TGI, Ollama) with a tool-capable model |
|
|
282
|
+
| Judge | same via `JUDGE_*`; may be the same endpoint |
|
|
283
|
+
| Runtime | `fastapi` (the LangGraph Server image checks for a licence at startup; the local `langgraph dev` server needs none) |
|
|
284
|
+
| Python deps | private index or mirror (`UV_INDEX_URL`), `install --locked` |
|
|
285
|
+
| Images | base images mirrored into `--registry` (`PYTHON_IMAGE` / `UV_IMAGE` build args); the chart's Bitnami subcharts vendored under `deployment/helm/<name>/charts/` and their images mirrored, otherwise `deploy` runs `helm dependency build` against `registry-1.docker.io` (exit 2 offline) |
|
|
286
|
+
| Tracing | `TRACING_ENABLED=true` with OTLP to an in-cluster collector, or off; no LangSmith |
|
|
287
|
+
| Evals | local datasets, deterministic checks, judge run in the project's environment against the on-network endpoint; `eval submit` disabled |
|
|
288
|
+
| CLI | installed from a mirror (`GRAPH_AGENTS_CLI_INSTALL_SPEC`); `GRAPH_AGENTS_CLI_NO_UPDATE_CHECK=1`; skills from the wheel bundle |
|
|
289
|
+
| Scaffold | built-in templates only |
|
|
290
|
+
| CD | only with an on-network GitHub Enterprise Server; otherwise `cd: skip` and direct-mode `deploy` |
|
|
291
|
+
|
|
292
|
+
`infra check --profile disconnected` and `login --profile disconnected` verify these and fail on
|
|
293
|
+
any hosted dependency. "Runs locally" (orchestration on the developer's machine) is not "runs
|
|
294
|
+
disconnected" (this profile).
|
|
295
|
+
|
|
296
|
+
## Troubleshooting
|
|
297
|
+
|
|
298
|
+
| Symptom | Fix |
|
|
299
|
+
|---|---|
|
|
300
|
+
| `deploy` exit 3 "No env file for <env>" | create `.env.<env>` with the allow-listed keys, or pass `--env-file`; `.env` is used for `dev` only |
|
|
301
|
+
| `deploy` exit 1 "Refusing to deploy to <env> on the kubeconfig's current context" | record `environments.<env>.context` in the manifest, pass `--context <name>`, or `--yes` after checking the printed context |
|
|
302
|
+
| `deploy` exit 3 "Kube context 'x' ... is not in the kubeconfig" | fix the manifest's context or `--context`; the known contexts are listed |
|
|
303
|
+
| `deploy` exit 1 "Secret ... is missing required key(s)" | add them to `.env.<env>` and re-run (direct), or run `secrets apply` (helm-push); or drop the key from `secrets.keys` if the environment does not need it |
|
|
304
|
+
| `deploy` exit 2 "Another helm operation ... is in progress" | wait for it (`helm history`); if nothing else runs, the printed `helm rollback` / `helm uninstall` clears the lock an interrupted helm left |
|
|
305
|
+
| `deploy` exit 2 "helm upgrade failed ... rolled back to revision N" | read the printed pod diagnostics (states, this rollout's events, logs); the Secret was restored too ("Secret ... was restored"); fix and deploy again |
|
|
306
|
+
| "Secret ... keeps this deploy's values for ..." after a failed deploy | the release stayed on the failed revision (`--no-atomic`, another deploy): roll it back, then re-apply the previous values with `secrets apply --env-file <previous file>` |
|
|
307
|
+
| `deploy` exit 3 "still hold(s) the placeholder CHANGE-ME" | set the real value (an API base URL, `OPENAI_BASE_URL`) in `values-<env>.yaml` or `values.yaml` |
|
|
308
|
+
| `deploy` / `infra check` "The jwt auth policy cannot verify tokens" | set `AUTH_JWT_JWKS_URL` (or `AUTH_JWT_PUBLIC_KEY`), `AUTH_JWT_ISSUER` and `AUTH_JWT_AUDIENCE` under `env:` in `values-<env>.yaml` (an empty value there overrides the Secret) |
|
|
309
|
+
| `deploy --status` exit 1 "did not complete within" | read the printed pods, events and logs; `--timeout` waits longer |
|
|
310
|
+
| `deploy --restart` exit 2 "did not become ready" | the old pods keep serving; fix the cause (often a Secret value) and restart again, or `kubectl rollout undo` |
|
|
311
|
+
| "No pods were replaced" / "The Secret changed ... run deploy --restart" | same image and chart values: the pods read a changed Secret only at start |
|
|
312
|
+
| Warning "POSTGRES_DSN does not require TLS" | add `sslmode=verify-full` (and `sslrootcert`) to the DSN; see `references/kubernetes.md` |
|
|
313
|
+
| `deploy` exit 1 "Refusing to deploy <env> from outside CI in helm-push mode" | run from the CI runner, or `--force-direct` for a deliberate workstation deploy (dev is always allowed) |
|
|
314
|
+
| `deploy` exit 1 "--env-file is not accepted in argocd mode" (or helm-push) | Secrets are applied separately: `secrets apply --env <env>`; `deploy --env <env> --image <ref>` only opens the PR (argocd) or runs helm (helm-push) |
|
|
315
|
+
| `deploy` exit 1 "the manifest records auth_policy_implemented: false" | implement `app/policies/custom.py`, flip the manifest flag |
|
|
316
|
+
| `build` / `deploy` exit 3 "still the placeholder 'ghcr.io/CHANGE-ME'" | `graph-agents-cli scaffold enhance --registry <host>/<org>` (sets `create_params.registry` in the manifest, `image.repository` in the chart values and `IMAGE_REPOSITORY` in `.github/agent.env`); `build` also takes `--registry` |
|
|
317
|
+
| `deploy` exit 3 "gateway.parentRef.name is blank" | set `gateway.parentRef.name` in `values-<env>.yaml` (or `gateway.enabled: false` / `ingress.enabled: true`) |
|
|
318
|
+
| chart error "image.tag is empty" / "must be a quoted string" | deploy with a built image (`deploy` passes the tag); quote tags in values files (`tag: "0123456"`) |
|
|
319
|
+
| `deploy` exit 3 "is a digest reference" | pass `<registry>/<repo>:<tag>`; the chart has no `image.digest` |
|
|
320
|
+
| `deploy` exit 3 "not committed on origin/main" (argocd) | commit `values-<env>.yaml` on `main` first; the PR is built from the base branch's copy, never the working tree |
|
|
321
|
+
| `secrets apply` exit 3 "must be single-line" | put the value on one line (for example base64) or create the Secret with kubectl directly |
|
|
322
|
+
| "API_KEY in <file> differs from the live Secret; the live key is kept" | intended; pass `--rotate-api-key` to replace it, then `deploy --restart` |
|
|
323
|
+
| A2A client dials `127.0.0.1:8000` after fetching the card | `APP_URL` is unset in the pod: set `appUrl` or a gateway/ingress hostname in the values file |
|
|
324
|
+
| An agent's calls to another agent fail with 403 "Delegated caller ... is not allowed here (AUTH_ALLOWED_ACTORS)" | list the id the error names (the `act.sub` of the caller's exchanged tokens) in the called agent's `AUTH_ALLOWED_ACTORS`: `system apply` lists the caller's `actor_id` (default its `client_id`), so set `actor_id` when the issuer names it differently; then `deploy` it |
|
|
325
|
+
| "<peer>'s agent card names <url> as its A2A endpoint, not the URL this agent calls" | set the called agent's `appUrl` to the URL the caller dials (`system apply` does); `graph-agents-cli system check --env <env>` (SC05) or `peer show <name> --check` finds it |
|
|
326
|
+
| `deploy` exit 2 "missing in charts/ directory" or `helm dependency build` failed (429) | `registry-1.docker.io` is unreachable or rate-limited; retry, authenticate, or vendor the charts under `deployment/helm/<name>/charts/` |
|
|
327
|
+
| `deploy` exit 2 naming a tool | helm, kubectl, docker, git or gh is not on `PATH` |
|
|
328
|
+
| Staging PR opened by CI never runs `pr_checks` | PRs opened with `GITHUB_TOKEN` do not trigger workflows; store a PAT or App token as `GH_PR_TOKEN` |
|
|
329
|
+
| helm-push job: "DEPLOY_KUBECONFIG is empty" | store the kubeconfig as the `DEPLOY_KUBECONFIG` secret of that GitHub environment |
|
|
330
|
+
| Workflow step "Load project settings" fails on `.github/agent.env` | only the six known names are accepted; rename `CLI_VERSION_PIN` to `GRAPH_AGENTS_CLI_SPEC` |
|
|
331
|
+
| `k3s ctr images import` permission denied | the import needs root on that host |
|
|
332
|
+
| Pod `CreateContainerConfigError` | the Secret `<name>-app` is missing (required outside dev): `secrets apply`, then `secrets status --env <env>` |
|
|
333
|
+
| Pod not Ready, `/ready` 503 | the database is unreachable from the pod: check the DSN in the Secret and network policies |
|
|
334
|
+
| `ImagePullBackOff` | pull secret missing (`imagePullSecrets` in values; `infra check` reports it) or the image was not pushed / loaded |
|
|
335
|
+
| No route / 404 at the hostname | `gateway.parentRef` or `ingress.className` unset, or the path is not in `route.publicPaths`; `infra check` lists classes |
|
|
336
|
+
| TLS errors | `tls.existingSecret` name wrong, or cert-manager not installed while `tls.certManager.enabled` |
|
|
337
|
+
| 401 from `run --url` | wrong credential for the policy; `secrets status`; pass `--header` |
|
|
338
|
+
| 503 on every request under `custom` | the stub is still in place |
|
|
339
|
+
| Argo shows `OutOfSync` after `--restart` | self-heal reverted the restart annotation; use an Argo resource action |
|
|
340
|
+
| `ApiPolicyError` in tool results after deploy (outside dev, clients see `The tool call did not succeed. Reference: <error_id>`; the pod log has `tool call failed (error_id=...)` with its `error_type`, and `api call refused: ...` naming the rule) | the deployed `api-policy.yaml` differs from local (it is baked into the image; rebuild), or a base URL / token variable is missing in the pod (`api call not sent`); "limits.max_calls_per_run" or "rate_per_minute" in the refusal means a limit was reached (per run / per replica) |
|
|
341
|
+
|
|
342
|
+
## Not covered by this skill
|
|
343
|
+
|
|
344
|
+
- Writing the auth policy or tools: `/graph-agents-cli-langgraph-code`.
|
|
345
|
+
- Adding the Kubernetes target or CD mode to a project: `/graph-agents-cli-scaffold`.
|
|
346
|
+
- The eval gate that precedes deployment: `/graph-agents-cli-eval`.
|
|
347
|
+
- Tracing configuration after deploy: `/graph-agents-cli-observability`.
|
|
348
|
+
- Installing cluster components (Gateway controller, cert-manager, Argo CD, metrics-server),
|
|
349
|
+
provisioning clusters or registries, or a managed-cloud deployment target: none exist here.
|
|
350
|
+
- External Secrets Operator, Sealed Secrets, Kustomize, Terraform, GitLab CI: not in this release.
|
|
351
|
+
|
|
352
|
+
## Migration note
|
|
353
|
+
|
|
354
|
+
Compared with google-agents-cli: Agent Runtime, Cloud Run, and GKE targets, Terraform
|
|
355
|
+
provisioning (`infra single-project`, `infra cicd`), Cloud Build, Secret Manager, and Agent
|
|
356
|
+
Gateway are gone. Any Kubernetes cluster via a Helm chart replaces them; secrets are Kubernetes
|
|
357
|
+
Secrets applied from allow-listed `.env` keys; `infra check` is read-only.
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
# Required GitHub settings
|
|
2
|
+
|
|
3
|
+
These are repository settings a workflow cannot create for itself with the default token. The
|
|
4
|
+
operator sets them once; `graph-agents-cli infra check` reports whether they exist when a
|
|
5
|
+
`GITHUB_TOKEN` (or `gh auth`) is available; the scaffolded README documents them. The CLI never
|
|
6
|
+
creates or changes them.
|
|
7
|
+
|
|
8
|
+
## Environments
|
|
9
|
+
|
|
10
|
+
| Environment | Settings |
|
|
11
|
+
|---|---|
|
|
12
|
+
| `production` | required reviewers (at least one); "prevent self-review" enabled; deployment branches restricted to `main`; optional wait timer; in `helm-push` mode the `DEPLOY_KUBECONFIG` secret |
|
|
13
|
+
| `staging` | deployment branches restricted to `main`; no reviewers; in `helm-push` mode the `DEPLOY_KUBECONFIG` secret |
|
|
14
|
+
|
|
15
|
+
The production jobs (`promote-to-prod` in both modes) declare `environment: production` and run
|
|
16
|
+
only from `main`.
|
|
17
|
+
|
|
18
|
+
## Branch protection on `main` (argocd and helm-push modes)
|
|
19
|
+
|
|
20
|
+
- Pull requests required.
|
|
21
|
+
- Required review from code owners.
|
|
22
|
+
- "Dismiss stale approvals" enabled.
|
|
23
|
+
- "Prevent self-approval" enabled.
|
|
24
|
+
- `pr_checks` as a required status check.
|
|
25
|
+
- No bypass for the Actions token, except the staging auto-merge mechanism (auto-merge allowed
|
|
26
|
+
on the repository; the staging PR merges once `pr_checks` passes).
|
|
27
|
+
|
|
28
|
+
## `CODEOWNERS`
|
|
29
|
+
|
|
30
|
+
Scaffolded at `.github/CODEOWNERS` for every project:
|
|
31
|
+
|
|
32
|
+
```
|
|
33
|
+
/deployment/ @CHANGE-ME/production-approvers # kubernetes target only
|
|
34
|
+
/deployment/helm/*/values-dev.yaml # unowned, so the staging PR can auto-merge
|
|
35
|
+
/deployment/helm/*/values-staging.yaml
|
|
36
|
+
/.github/ @CHANGE-ME/production-approvers # workflows, agent.env, this file
|
|
37
|
+
/api-policy.yaml @CHANGE-ME/production-approvers
|
|
38
|
+
/tests/eval/ @CHANGE-ME/production-approvers
|
|
39
|
+
/graph-agents-cli-extensions.yaml @CHANGE-ME/production-approvers
|
|
40
|
+
/extensions/ @CHANGE-ME/production-approvers
|
|
41
|
+
/.graph-agents-cli/ @CHANGE-ME/production-approvers
|
|
42
|
+
/graph-agents-cli-manifest.yaml @CHANGE-ME/production-approvers
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Replace the placeholder team (`infra check` reports it: a required item under `helm-push` or
|
|
46
|
+
`argocd`, a warning under `skip`; GitHub ignores unknown owners, so the gate would require
|
|
47
|
+
nobody). With code-owner review required, a PR touching `values-prod.yaml`, the policy, the eval
|
|
48
|
+
gate inputs, the workflows or the extensions cannot merge without a production approver, whoever
|
|
49
|
+
opened it.
|
|
50
|
+
|
|
51
|
+
## Secrets and variables
|
|
52
|
+
|
|
53
|
+
| Name | Kind | Mode | Purpose |
|
|
54
|
+
|---|---|---|---|
|
|
55
|
+
| (none for images on GHCR) | | argocd, helm-push | `GITHUB_TOKEN` pushes to `ghcr.io/<org>` |
|
|
56
|
+
| `REGISTRY_USERNAME`, `REGISTRY_PASSWORD` | repository secrets | any CD mode with a non-GHCR registry | `docker login` in `staging.yaml` |
|
|
57
|
+
| `DEPLOY_KUBECONFIG` | **environment** secret of `staging` and of `production` | helm-push | the self-hosted runner's cluster credentials, written under `RUNNER_TEMP` and removed after the job. Never a repository secret: any branch's workflow could read that one and it would bypass the production reviewers. The retired repository secret `KUBECONFIG` is no longer read; delete it |
|
|
58
|
+
| `GH_PR_TOKEN` | repository secret | argocd, helm-push | a fine-grained PAT or GitHub App token with pull-request and contents write access, used to push the desired-state branches and open the PRs (`secrets.GH_PR_TOKEN \|\| secrets.GITHUB_TOKEN`). A PR opened with the workflow `GITHUB_TOKEN` does not trigger `pr_checks`, so auto-merge on a required check needs it |
|
|
59
|
+
| provider key (`OPENAI_API_KEY`, `ANTHROPIC_API_KEY`, `GOOGLE_API_KEY` or `MODEL_API_KEY`) | repository secret | any | the `pr_checks` eval gate runs on the project's real provider when its key exists; tests always run on the fake model |
|
|
60
|
+
| `MODEL_PROVIDER`, `MODEL_NAME` | repository variables | any | override the eval gate's model (`MODEL_NAME` is required when `MODEL_PROVIDER` differs from the project's provider) |
|
|
61
|
+
| `JUDGE_MODEL_PROVIDER`, `JUDGE_MODEL_NAME`, `JUDGE_BASE_URL`; `JUDGE_API_KEY` | variables; secret | any | a separate eval judge |
|
|
62
|
+
|
|
63
|
+
Without a provider key the gate runs on the deterministic fake model and prints the warning
|
|
64
|
+
"Eval gate is not a quality signal". **Never** application secrets (`API_KEY`, `POSTGRES_DSN`,
|
|
65
|
+
provider keys for the deployed app) in GitHub: those are Kubernetes Secrets applied by the owner
|
|
66
|
+
(`secrets.md`).
|
|
67
|
+
|
|
68
|
+
## Self-hosted runner (helm-push)
|
|
69
|
+
|
|
70
|
+
A runner with network access to the cluster (the jobs use `runs-on: self-hosted`), with `kubectl`
|
|
71
|
+
and `curl` on `PATH` (the jobs resolve the kube context and verify the rollout with them; `uv` is
|
|
72
|
+
installed by the job). Its kubeconfig (`DEPLOY_KUBECONFIG`) needs rights to deploy the release
|
|
73
|
+
and to read the app Secret (deploy checks its required keys).
|
|
74
|
+
|
|
75
|
+
## GitHub Enterprise Server
|
|
76
|
+
|
|
77
|
+
Set `GH_HOST=<host>` (or `GITHUB_HOST`; `GITHUB_SERVER_URL` is honoured inside Actions) with
|
|
78
|
+
`GH_ENTERPRISE_TOKEN` or `GITHUB_TOKEN` where `deploy` runs, so argocd-mode PRs go to that host
|
|
79
|
+
(API base `https://<host>/api/v3`). `infra check --profile disconnected` and
|
|
80
|
+
`login --profile disconnected` treat GitHub-hosted CI as outside the disconnected profile unless
|
|
81
|
+
`GH_HOST` / `GITHUB_SERVER_URL` names an on-network GHES.
|
|
82
|
+
|
|
83
|
+
## What `infra check` reports
|
|
84
|
+
|
|
85
|
+
Through the `gh` CLI (`gh api`, so `gh auth login` or `GITHUB_TOKEN`), skipped when `cd: skip`:
|
|
86
|
+
whether the `production` environment exists with required reviewers, prevent self-review and
|
|
87
|
+
deployment branches restricted; whether the `staging` environment exists with restricted
|
|
88
|
+
branches; whether `main` branch protection requires pull requests, code-owner review, dismisses
|
|
89
|
+
stale approvals and lists `pr_checks` as a required status check. For `helm-push` it also
|
|
90
|
+
reports whether `DEPLOY_KUBECONFIG` exists as a secret of each environment and warns about a
|
|
91
|
+
repository-level (or shared organization) `KUBECONFIG` / `DEPLOY_KUBECONFIG` secret; these rows
|
|
92
|
+
are informational when the account cannot read secrets. When the GitHub API does not answer, the
|
|
93
|
+
GitHub rows collapse into one informational row. Independently of GitHub it reports every
|
|
94
|
+
`CHANGE-ME` placeholder (registry, chart `image.repository` and `env` (required outside dev,
|
|
95
|
+
a warning in dev, as `deploy` treats it), CODEOWNERS, Argo CD `repoURL`), and with `--env` the
|
|
96
|
+
`jwt` policy's verification settings (a JWKS URL or public key; issuer and audience outside
|
|
97
|
+
dev), the ServiceMonitor's token Secret and whether an external DSN requires TLS. Rows for
|
|
98
|
+
components the environment does not use (a disabled Gateway, cert-manager, metrics-server,
|
|
99
|
+
Argo CD) are `skip` with no install hint. It never changes anything.
|
|
100
|
+
|
|
101
|
+
```bash
|
|
102
|
+
GITHUB_TOKEN=... graph-agents-cli infra check --env prod --json
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
## Verifying by hand
|
|
106
|
+
|
|
107
|
+
```bash
|
|
108
|
+
gh api repos/<owner>/<repo>/environments
|
|
109
|
+
gh api repos/<owner>/<repo>/environments/production
|
|
110
|
+
gh api repos/<owner>/<repo>/environments/production/secrets
|
|
111
|
+
gh api repos/<owner>/<repo>/branches/main/protection
|
|
112
|
+
gh api repos/<owner>/<repo> --jq .allow_auto_merge
|
|
113
|
+
```
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
# GitOps: the `argocd` CD mode
|
|
2
|
+
|
|
3
|
+
With `cd: argocd`, Argo CD inside the cluster reconciles from `main`. `graph-agents-cli deploy`
|
|
4
|
+
never runs helm, never contacts the cluster and never merges; it writes desired state and opens
|
|
5
|
+
a pull request.
|
|
6
|
+
|
|
7
|
+
## Scaffolded artefacts
|
|
8
|
+
|
|
9
|
+
- `deployment/argocd/application-<env>.yaml`: one Argo `Application` per environment;
|
|
10
|
+
`targetRevision: main`, `path: deployment/helm/<name>`,
|
|
11
|
+
`valueFiles: [values.yaml, values-<env>.yaml]`, destination namespace `<name>-<env>`
|
|
12
|
+
(`CreateNamespace`). `dev` and `staging` have automated sync with self-heal; **prod has no
|
|
13
|
+
automated sync** (an operator syncs in Argo after the merge). They ignore the data of the
|
|
14
|
+
chart-managed `<name>-postgresql-auth` Secret (`RespectIgnoreDifferences`), so the dev database
|
|
15
|
+
password is not regenerated on every sync. Set `repoURL` (a `CHANGE-ME` placeholder that
|
|
16
|
+
`infra check` reports). An environment shows a comparison error until its values file has an
|
|
17
|
+
image tag: the chart refuses an empty one.
|
|
18
|
+
- `.github/workflows/pr_checks.yaml`: ruff, unit and integration tests on the fake model, `lint`
|
|
19
|
+
(with the API-policy check) and the eval gate. The gate uses the project's real provider when
|
|
20
|
+
its key is a repository secret (or the `MODEL_PROVIDER` / `MODEL_NAME` repository variables);
|
|
21
|
+
on the fake model it warns that the gate only checks the plumbing.
|
|
22
|
+
- `.github/workflows/staging.yaml` (on `main`, or by hand from `main`): builds and pushes
|
|
23
|
+
`<registry>/<name>:<short sha>` (`${GITHUB_SHA::7}`), then writes the tag (double-quoted) into
|
|
24
|
+
`values-staging.yaml` on branch `deploy/staging/<short sha>`, built on the latest `main`, and
|
|
25
|
+
opens a PR with auto-merge (`gh pr merge --auto --squash`); branch protection must permit
|
|
26
|
+
auto-merge. It closes older open `deploy/staging/*` PRs it supersedes (with a comment, deleting
|
|
27
|
+
their branches) and does nothing when `main` or an open PR already carries this build or a
|
|
28
|
+
newer one, so a re-run of an older build never moves staging back. PRs whose tag is not a
|
|
29
|
+
commit (a workstation `<sha>-dirty-<time>`) are left alone. Pushes that only change
|
|
30
|
+
`values-*.yaml` do not start the workflow, so a merged staging PR never triggers another build.
|
|
31
|
+
- `.github/workflows/promote-to-prod.yaml`: runs in the GitHub `production` environment (which
|
|
32
|
+
controls who may *initiate* a promotion from CI), only from `main`; its `image_tag` input is the
|
|
33
|
+
short sha (empty = the tag in `values-staging.yaml`). It runs
|
|
34
|
+
`uvx --from "$GRAPH_AGENTS_CLI_SPEC" graph-agents-cli deploy --env prod --image <registry>/<name>:<short sha> --yes`,
|
|
35
|
+
which opens a PR updating `values-prod.yaml`. It does not merge.
|
|
36
|
+
- Both workflows use `secrets.GH_PR_TOKEN || secrets.GITHUB_TOKEN`. A pull request opened with
|
|
37
|
+
the workflow `GITHUB_TOKEN` does not trigger `pr_checks` (GitHub never starts workflows from
|
|
38
|
+
`GITHUB_TOKEN` events), so auto-merge on a required check needs a fine-grained PAT or GitHub
|
|
39
|
+
App token stored as the `GH_PR_TOKEN` repository secret, with pull-request **and contents**
|
|
40
|
+
write access (the staging job pushes the branch with it).
|
|
41
|
+
- Every job that runs graph-agents-cli sets `GRAPH_AGENTS_CLI_DISABLE_OVERRIDES=1`, so project or
|
|
42
|
+
user extensions cannot replace `lint`, `eval` or `deploy` in CI and CD.
|
|
43
|
+
- `.github/agent.env` (rendered for every project, read only by the workflows): `IMAGE_REPOSITORY`,
|
|
44
|
+
`RELEASE_NAME`, `CHART_PATH`, `RUNTIME`, `CD` and `GRAPH_AGENTS_CLI_SPEC` (where CI installs the
|
|
45
|
+
CLI: the creating version's git tag). It is data, never sourced: one `NAME=VALUE` per line, `#`
|
|
46
|
+
comments and blank lines skipped, one pair of surrounding quotes and a trailing ` # comment`
|
|
47
|
+
dropped. Any other name (including the retired `CLI_VERSION_PIN`), a duplicate or a control
|
|
48
|
+
character fails the `Load project settings` step before anything is exported. To add a setting,
|
|
49
|
+
extend `known` in all three workflows.
|
|
50
|
+
- `.github/CODEOWNERS`: `/.github/`, `/CODEOWNERS`, `/api-policy.yaml`, `/tests/eval/`, the
|
|
51
|
+
extensions files, the manifest, and `/deployment/` except `values-dev.yaml` and
|
|
52
|
+
`values-staging.yaml` (left unowned so the staging PR can auto-merge) ->
|
|
53
|
+
`@CHANGE-ME/production-approvers` (placeholder to fill; `infra check` reports it).
|
|
54
|
+
|
|
55
|
+
The `Application` manifests and the values files are config: `upgrade` never overwrites them.
|
|
56
|
+
|
|
57
|
+
## The `deploy` PR flow
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
graph-agents-cli deploy --env staging --image ghcr.io/acme/my-agent:abc1234
|
|
61
|
+
graph-agents-cli deploy --env prod --image ghcr.io/acme/my-agent:abc1234
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
1. Reads `values-<env>.yaml` **as `origin/main` holds it** (`git cat-file blob origin/main:<path>`;
|
|
65
|
+
`HEAD` when `origin/main` is unavailable), changes `image.tag` and nothing else. Your working
|
|
66
|
+
tree is not modified and never used: a checkout behind `main` or with local edits cannot leak
|
|
67
|
+
into the PR, and "nothing to change" is judged on the base branch (a closed, unmerged PR is
|
|
68
|
+
re-opened by a re-run). A values file not committed on the base is exit 3. Paths are
|
|
69
|
+
repository-relative, so a project below the git root works.
|
|
70
|
+
2. Builds branch `deploy/<env>/<short sha>` with git plumbing (`hash-object --stdin`,
|
|
71
|
+
`read-tree`, `update-index`, `write-tree`, `commit-tree`, `update-ref`) and pushes it with
|
|
72
|
+
`git push --force-with-lease=refs/heads/<branch>:<sha on origin>`; when `origin/<branch>`
|
|
73
|
+
already holds the change it prints "nothing to push", so a retry is idempotent. Your checkout
|
|
74
|
+
and index are never switched. A git identity must be configured (`commit-tree` needs one; the
|
|
75
|
+
scaffolded workflow sets it).
|
|
76
|
+
3. Opens or updates a PR against `main` with `gh` when available, else GitHub REST with
|
|
77
|
+
`GITHUB_TOKEN`, `GH_TOKEN` or `GH_ENTERPRISE_TOKEN`. Only GitHub and GitHub Enterprise Server
|
|
78
|
+
hosts are supported; a GHES host is recognised from `GH_HOST` (or `GITHUB_HOST`,
|
|
79
|
+
`GITHUB_SERVER_URL`), API base `https://<host>/api/v3`. Without `gh` and without a token the
|
|
80
|
+
branch is still pushed and the command exits 3 with instructions.
|
|
81
|
+
4. Prints the PR URL and stops. **You never merge it.** Argo reconciles after the merge.
|
|
82
|
+
|
|
83
|
+
`deploy` prints "No cluster is contacted" in this mode: no kube context is used, so `--context`
|
|
84
|
+
and `--yes` change nothing here. `--env-file` and `--rotate-api-key` are refused (exit 1):
|
|
85
|
+
Secrets are applied with `secrets apply`. `--dry-run` prints the values rewrite, the git plumbing
|
|
86
|
+
and the `gh pr list/create` commands. `--image` names the CI-pushed image (a tagged reference; a
|
|
87
|
+
digest reference is refused with exit 3 because the chart has no `image.digest`; a repository
|
|
88
|
+
other than the chart's `image.repository` gets a warning, since only `image.tag` is written);
|
|
89
|
+
without it `deploy` uses `--tag` or the short git sha and warns that the image must already have
|
|
90
|
+
been pushed by CI (the CLI does not build or push in this mode). A chart `image.repository` that
|
|
91
|
+
still holds `CHANGE-ME` is exit 3.
|
|
92
|
+
|
|
93
|
+
## The single production gate
|
|
94
|
+
|
|
95
|
+
Production desired state changes only through a PR touching `values-prod.yaml`. Two paths open
|
|
96
|
+
such a PR (`promote-to-prod` from CI, `deploy --env prod` from a workstation); neither merges.
|
|
97
|
+
The merge requires:
|
|
98
|
+
|
|
99
|
+
- review from the production approvers in `CODEOWNERS` for `values-prod.yaml`,
|
|
100
|
+
- no self-approval (branch protection "prevent self-approval" and environment "prevent
|
|
101
|
+
self-review"),
|
|
102
|
+
- `pr_checks` green.
|
|
103
|
+
|
|
104
|
+
Argo watches `main`, so approval necessarily precedes the production change on both paths. No
|
|
105
|
+
inbound access from GitHub to the cluster exists. No Argo Image Updater is used. After deploying,
|
|
106
|
+
Argo's own health assessment (the readiness probe on `/ready`) shows whether the rollout landed;
|
|
107
|
+
the workflows have no cluster access by design.
|
|
108
|
+
|
|
109
|
+
## Operating in argocd environments
|
|
110
|
+
|
|
111
|
+
| Need | Command |
|
|
112
|
+
|---|---|
|
|
113
|
+
| Status | `graph-agents-cli deploy --status --env <env>` (`argocd app get <name>-<env>`; without the `argocd` CLI a bounded `kubectl rollout status` plus the pods' readiness, exit 1 when not ready) |
|
|
114
|
+
| Restart after secret rotation | `graph-agents-cli deploy --restart --env <env>` (`kubectl rollout restart`, then waits for the new pods); the CLI warns that self-heal may revert the annotation and recommends an Argo resource action (`argocd app actions run <name>-<env> restart --kind Deployment`) |
|
|
115
|
+
| Secrets | `graph-agents-cli secrets apply/status --env <env>` from the owner's workstation; Argo never manages the app Secret |
|
|
116
|
+
| Rollback | revert the values change on `main` through a PR (same gate); for emergencies `argocd app history` / `argocd app rollback` on the Argo side, then reconcile git |
|
|
117
|
+
| Diff before merge | `argocd app diff <name>-<env> --revision <branch>` |
|
|
118
|
+
|
|
119
|
+
`--status`, `--restart` and `secrets` follow the kube context rules (recorded context or
|
|
120
|
+
`--context`; outside dev the current context needs a confirmation or `--yes`). Direct
|
|
121
|
+
`helm upgrade` or `kubectl apply` against an argocd environment is drift: self-heal reverts it
|
|
122
|
+
(dev, staging) or Argo reports `OutOfSync` (prod). Do not do it.
|
|
123
|
+
|
|
124
|
+
## `helm-push` for comparison
|
|
125
|
+
|
|
126
|
+
A self-hosted GitHub runner inside the network gets the cluster credentials from the
|
|
127
|
+
`DEPLOY_KUBECONFIG` secret of the `staging` or `production` **environment** (written under
|
|
128
|
+
`RUNNER_TEMP` and removed after the job), resolves one kube context (the manifest's
|
|
129
|
+
`environments.<env>.context`, else the kubeconfig's current one), runs
|
|
130
|
+
`graph-agents-cli deploy --env <env> --image <ref> --context "$KUBE_CONTEXT" --yes` (helm only),
|
|
131
|
+
and verifies the rollout (`kubectl rollout status`, `/health` and `/ready` through a
|
|
132
|
+
port-forward; the runner needs `kubectl` and `curl`). The `production` job declares
|
|
133
|
+
`environment: production` and is gated by that environment's reviewers. Workstation deploys are
|
|
134
|
+
allowed for `dev`; `staging`/`prod` are refused outside CI (`GITHUB_ACTIONS=true`) even with
|
|
135
|
+
`--image`, unless `--force-direct`. Secrets are still provisioned by the owner from a
|
|
136
|
+
workstation, never by CI; the runner's kubeconfig needs permission to read the Secret (deploy
|
|
137
|
+
checks its required keys).
|