chore(deploy): 收口 legacy compose/脚本并同步 cd-production 引用 (#1527 PR2) - #1590
Conversation
📝 WalkthroughWalkthroughProduction deployment now uses the authoritative Compose configuration and relocated environment template. Legacy deployment scripts, Compose files, proxy configurations, templates, and operational assets are removed. Deployment checks and readiness tests enforce the new structure. ChangesProduction deployment consolidation
Estimated code review effort: 3 (Moderate) | ~25 minutes Sequence Diagram(s)sequenceDiagram
participant CDWorkflow as cd-production.yml
participant Compose as Docker Compose
participant HubServer as hub-server
participant API as Production API
CDWorkflow->>Compose: Start production services
Compose->>HubServer: Recreate hub-server with tagged image
CDWorkflow->>API: Perform manual health verification
CDWorkflow->>Compose: Inspect production logs
Possibly related PRs
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
5ce2d27 to
0ab5950
Compare
#1527 PR1(cfde8494)已确立 deployments/production/docker-compose.yml 为权威 production compose SSOT 并挂 verify-deployment-shape 门禁;本 PR 完成 PR2 收口: - 删除 hub-server/deployments 下旧独立 PG+Redis 拓扑资产:docker-compose.prod.yml、 docker-compose.us1.yml、hk2/(compose + deploy-hk2.sh + deploy-web-hk2.sh + nginx/env 模板)、deploy.sh、Caddyfile/Caddyfile.prod、.env.production.example、 backup-cron、.dockerignore(构建上下文为仓库根,消费根 .dockerignore)。 - 保留构建输入:Dockerfile、docker-entrypoint.sh(Dockerfile COPY 依赖); README.md 精简为构建输入说明(verify-doc-ssot 要求保留 "Live host" marker)。 - verify-deployment-shape.ps1 遗留清单由"注册制"改为"关闭态": hub-server/deployments/ 下出现任何 compose 文件即 FAIL;自测 5/5 通过, 含"新增第二份手维护 production compose 必 FAIL"回归。 - cd-pr-check.yml 移除 deploy.sh / .env.production.example 检查与 deploy.sh 结构校验 step;cd-production.yml 部署/回滚/health-check 指引回显全部改指 deployments/production/docker-compose.yml(仅引用同步,未动行为/权限/secrets)。 - verify-web-deploy-readiness.ps1 生产 OIDC 断言改指权威 compose + 权威 .env.example(env 模板补 OIDC 回调/交换端点/loopback 说明段)。 - docs/architecture/05-deployment.md inventory 表更新为最终形态。 未删 Dockerfile,未触碰 checks.yml / release.yml / cd-hub-server.yml, 未修改真实服务器/secret/生产部署。
0ab5950 to
d19ea98
Compare
There was a problem hiding this comment.
Actionable comments posted: 5
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In @.github/workflows/cd-production.yml:
- Around line 128-132: Update the staging deployment instructions at
.github/workflows/cd-production.yml lines 128-132 and the production deployment
instructions at .github/workflows/cd-production.yml lines 191-196 so Docker
Compose starts the image selected by this workflow rather than the default
latest image; consistently tag the pulled image as latest or pass the selected
image tag or digest to the compose deployment command at both sites.
- Around line 191-196: The production workflow references docker-build-push
outputs without declaring the job as a direct dependency. Update the needs
declarations for approve-production and deploy-production to include
docker-build-push, and add it to health-check as well if that job must access
the actual image tag and digest instead of N/A; preserve the existing approval
and deployment ordering.
In `@deployments/production/.env.example`:
- Around line 17-24: Remove real production addresses from
deployments/production/.env.example lines 17-24 and replace the OAuth callback
with a placeholder. In .github/workflows/cd-production.yml lines 194-196 and
270-273, replace concrete production API addresses with placeholders. In
scripts/release/verify-web-deploy-readiness.ps1 lines 183-188, load the required
production domains from protected external verification configuration rather
than hardcoding them; apply the same repository policy consistently across all
four sites.
In `@scripts/release/verify-web-deploy-readiness.ps1`:
- Around line 183-188: Update the readiness assertions in the verification
script to avoid hard-coded production domains or server addresses. Move the
concrete callback and endpoint values used by these Assert-Contains checks into
the external server SSOT or protected verification configuration, then have the
checks reuse those injected values while preserving validation of the production
environment and compose settings.
In `@scripts/verify/verify-deployment-shape.ps1`:
- Around line 127-136: The legacy compose inventory check in Get-ChildItem must
detect both .yml and .yaml compose filenames under the legacy deployment
directory. Update scripts/verify/verify-deployment-shape.ps1 lines 127-136
accordingly, and add a .yaml resurrection fixture plus an assertion for the same
“legacy compose inventory closed” failure reason in
scripts/verify/tests/verify-deployment-shape.Tests.ps1 lines 94-110.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro Plus
Run ID: a66e47c1-0983-4036-980b-70c554fb6b3c
📒 Files selected for processing (22)
.github/workflows/cd-pr-check.yml.github/workflows/cd-production.ymldeployments/production/.env.exampledocs/architecture/05-deployment.mdhub-server/deployments/.dockerignorehub-server/deployments/.env.production.examplehub-server/deployments/Caddyfilehub-server/deployments/Caddyfile.prodhub-server/deployments/README.mdhub-server/deployments/backup-cronhub-server/deployments/deploy.shhub-server/deployments/docker-compose.prod.ymlhub-server/deployments/docker-compose.us1.ymlhub-server/deployments/hk2/.env.examplehub-server/deployments/hk2/deploy-hk2.shhub-server/deployments/hk2/deploy-web-hk2.shhub-server/deployments/hk2/docker-compose.hk2.ymlhub-server/deployments/hk2/nginx-hk2-v2.confhub-server/deployments/hk2/nginx-hk2.confscripts/release/verify-web-deploy-readiness.ps1scripts/verify/tests/verify-deployment-shape.Tests.ps1scripts/verify/verify-deployment-shape.ps1
💤 Files with no reviewable changes (14)
- hub-server/deployments/hk2/nginx-hk2.conf
- hub-server/deployments/backup-cron
- hub-server/deployments/hk2/docker-compose.hk2.yml
- hub-server/deployments/hk2/nginx-hk2-v2.conf
- hub-server/deployments/.dockerignore
- hub-server/deployments/Caddyfile
- hub-server/deployments/hk2/.env.example
- hub-server/deployments/docker-compose.us1.yml
- hub-server/deployments/Caddyfile.prod
- hub-server/deployments/docker-compose.prod.yml
- hub-server/deployments/.env.production.example
- hub-server/deployments/deploy.sh
- hub-server/deployments/hk2/deploy-hk2.sh
- hub-server/deployments/hk2/deploy-web-hk2.sh
| echo " 2. 部署: docker compose -f deployments/production/docker-compose.yml up -d --no-build" | ||
| echo " (本次构建镜像: ghcr.io/tokendancelab/agenthub-hub-server:${{ needs.docker-build-push.outputs.image_tag }})" | ||
| echo " 3. 验证: curl -s http://localhost:8090/health/ready (应返回 status=ok 且 ready=true)" | ||
| echo "" | ||
| echo "部署脚本与指南: hub-server/deployments/deploy.sh / hub-server/deployments/README.md" | ||
| echo "部署形状与指南: deployments/production/docker-compose.yml / docs/architecture/05-deployment.md" |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
Make Compose consume the image selected by this workflow.
Both instructions pull ${image_tag}, but the authoritative Compose file starts the latest tag. A non-stable release can therefore start an older image.
.github/workflows/cd-production.yml#L128-L132: tag the pulled staging image aslatest, or pass its tag or digest to Compose..github/workflows/cd-production.yml#L191-L196: apply the same image-selection mechanism in production.
🧰 Tools
🪛 zizmor (1.28.0)
[info] 129-129: code injection via template expansion (template-injection): may expand into attacker-controllable code
(template-injection)
📍 Affects 1 file
.github/workflows/cd-production.yml#L128-L132(this comment).github/workflows/cd-production.yml#L191-L196
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In @.github/workflows/cd-production.yml around lines 128 - 132, Update the
staging deployment instructions at .github/workflows/cd-production.yml lines
128-132 and the production deployment instructions at
.github/workflows/cd-production.yml lines 191-196 so Docker Compose starts the
image selected by this workflow rather than the default latest image;
consistently tag the pulled image as latest or pass the selected image tag or
digest to the compose deployment command at both sites.
| echo " 2. 部署: docker compose -f deployments/production/docker-compose.yml up -d --no-build" | ||
| echo " (本次构建镜像: ghcr.io/tokendancelab/agenthub-hub-server:${{ needs.docker-build-push.outputs.image_tag }})" | ||
| echo " compose 模板含 healthcheck;部署后人工验证见下方清单。" | ||
| echo " 3. 手动复核: curl -s https://api.hub.vectorcontrol.tech/health" | ||
| echo "" | ||
| echo "部署脚本与指南: hub-server/deployments/deploy.sh / hub-server/deployments/README.md" | ||
| echo "部署形状与指南: deployments/production/docker-compose.yml / docs/architecture/05-deployment.md" |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== workflow excerpt =="
cat -n .github/workflows/cd-production.yml | sed -n '1,240p'
echo
echo "== job/dependency references =="
python3 - <<'PY'
from pathlib import Path
import re
p = Path(".github/workflows/cd-production.yml")
text = p.read_text()
for job in re.findall(r'^[\w-]+:.*?(?=\n\w|$)', text, flags=re.S | re.M):
first=line=0
for i, j in enumerate(text.splitlines(), 1):
if j.rstrip().startswith(job.rstrip()):
first=j; line=i; break
print(f"JOB {first.strip()} at line {line}")
for m in re.finditer(r'^\s+(needs|uses|with)?:', job, flags=re.M):
print(f" line {text.count(chr(10),0,m.start())+1}: {m.group(0).strip()}")
PY
echo
echo "== yaml structural parse for needs =="
python3 - <<'PY'
from pathlib import Path
import re
text = Path(".github/workflows/cd-production.yml").read_text()
jobs = {}
current = None
for line in text.splitlines():
stripped = line.rstrip()
depth = len(line) - len(line.lstrip())
if stripped.endswith(":") and depth == 2 and not stripped.startswith("jobs:"):
current = stripped[:-1]
jobs.setdefault(current, {"needs": [], "refs": []})
job = jobs[current]
if current and depth == 4 and stripped.startswith("needs:"):
# inline list
m = re.match(r'needs:\s*\[(.*?)\]', stripped)
if m: job["needs"].extend(x.strip() for x in m.group(1).split(","))
else:
# multiline list
buf = [stripped]
for nxt in text.splitlines()[text.splitlines().index(stripped):]:
pass
print(json.dumps(jobs, indent=2, sort_keys=True))
PYRepository: TokenDanceLab/AgentHub
Length of output: 12467
🌐 Web query:
GitHub Actions context needs only jobs listed in needs key indirect needs context
💡 Result:
In GitHub Actions, the needs context provides access only to the outputs and results of jobs explicitly defined as direct dependencies of the current job [1][2][3]. It does not include data from "indirect" or transitive dependencies—that is, jobs that your dependencies depend on [1][3]. Key technical points: - Scope: The needs object is only populated for jobs that have one or more jobs listed in their needs key [1]. - Direct Only: You can only reference <job_id> in the needs context if that specific job ID is explicitly listed in your current job's needs configuration [1][2][3]. Attempting to access an indirect dependency's output or result via the needs context will fail or result in an empty/undefined value [4][1]. - Propagation Behavior: While needs data is not transitively available, the lifecycle of jobs is still subject to the Directed Acyclic Graph (DAG) logic [5]. If a job fails or is skipped, GitHub Actions will propagate that status downstream, causing dependent jobs to be skipped unless they use conditional expressions like if: always() or if: !cancelled() to override the default behavior [6][5][7]. - Troubleshooting: If you require data from a job that is not a direct dependency, you must either explicitly add that job to the current job's needs array or pass the required information through an intermediate job [8][1]. Workaround patterns for conditional job execution often involve using if conditions to handle the inherited skipped status caused by upstream failures in the dependency chain [6][5].
Citations:
- 1: https://docs.github.com/en/actions/reference/workflows-and-actions/contexts
- 2: https://github.com/github/docs/blob/main/content/actions/reference/workflows-and-actions/contexts.md
- 3: clarify
needs context contains outputs from all jobs that are defined as a dependency of the current jobgithub/docs#20701 - 4: https://kordis.store/spaceplayentry/github-actions-expressions-contexts
- 5: https://dev.to/cloud-sky-ops/mastering-github-actions-insights-and-pitfalls-of-if-conditions-1j87
- 6: Jobs skipped when NEEDS job ran successfully actions/runner#2205
- 7: https://docs.github.com/en/actions/how-tos/write-workflows/choose-what-workflows-do/use-jobs
- 8: https://stackoverflow.com/questions/64722037/github-actions-can-the-effects-of-one-job-trigger-another
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== deploy-production job block =="
cat -n .github/workflows/cd-production.yml | sed -n '173,270p'
echo
echo "== jobs and direct needs =="
python3 - <<'PY'
import yaml
from pathlib import Path
doc = yaml.safe_load(Path(".github/workflows/cd-production.yml"))
for job_id, job in doc.get("jobs", {}).items():
print(f"{job_id}: needs={job.get('needs')}, outputs={list(job.get('outputs', {}).keys())}")
PYRepository: TokenDanceLab/AgentHub
Length of output: 6111
Make docker-build-push a direct dependency.
deploy-production lists only approve-production, but reads needs.docker-build-push.outputs.image_tag and image_digest. GitHub Actions exposes only direct needs, so these values can be empty unless the dependency is added through the approval job or forwarded via explicit job outputs.
Add docker-build-push to approve-production/deploy-production, and to health-check if it should receive the actual image values instead of N/A.
🧰 Tools
🪛 zizmor (1.28.0)
[info] 192-192: code injection via template expansion (template-injection): may expand into attacker-controllable code
(template-injection)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In @.github/workflows/cd-production.yml around lines 191 - 196, The production
workflow references docker-build-push outputs without declaring the job as a
direct dependency. Update the needs declarations for approve-production and
deploy-production to include docker-build-push, and add it to health-check as
well if that job must access the actual image tag and digest instead of N/A;
preserve the existing approval and deployment ordering.
| # ── TokenDance ID OIDC 说明(字段定义见 docker-compose.yml 同目录)── | ||
| # 生产 OAuth 回调为公网 Web 浏览器回调: | ||
| # https://hub.vectorcontrol.tech/auth/tokendance/callback | ||
| # Hub 在 Web/Desktop 提交 code、state、PKCE verifier、device 与 redirect_uri 后, | ||
| # 通过 POST /client/auth/oidc/callback 完成代码交换(Hub 侧交换端点)。 | ||
| # http://127.0.0.1/callback 仅保留给 Desktop/native 动态 loopback 端口; | ||
| # 生产 compose 的 ALLOWED_REDIRECT_URIS 固定为 Web 回调,不放 loopback。 | ||
| # OIDC client 注册与 secret 由 TokenDance ID 管理,禁止写入仓库。 |
There was a problem hiding this comment.
🔒 Security & Privacy | 🟠 Major | ⚡ Quick win
Remove real production server addresses from repository files.
The same repository-policy violation appears in environment guidance, deployment guidance, and readiness checks. Keep concrete production addresses in the external server SSOT.
deployments/production/.env.example#L17-L24: replace the concrete callback address with a placeholder..github/workflows/cd-production.yml#L194-L196: replace the concrete production API address with a placeholder..github/workflows/cd-production.yml#L270-L273: replace the concrete production API addresses with placeholders.scripts/release/verify-web-deploy-readiness.ps1#L183-L188: inject concrete production domains through protected external verification configuration.
As per coding guidelines, “禁止提交 .env、API key、token、cookie、私钥、证书、SSH 配置、真实服务器或内网地址”.
📍 Affects 3 files
deployments/production/.env.example#L17-L24(this comment).github/workflows/cd-production.yml#L194-L196.github/workflows/cd-production.yml#L270-L273scripts/release/verify-web-deploy-readiness.ps1#L183-L188
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@deployments/production/.env.example` around lines 17 - 24, Remove real
production addresses from deployments/production/.env.example lines 17-24 and
replace the OAuth callback with a placeholder. In
.github/workflows/cd-production.yml lines 194-196 and 270-273, replace concrete
production API addresses with placeholders. In
scripts/release/verify-web-deploy-readiness.ps1 lines 183-188, load the required
production domains from protected external verification configuration rather
than hardcoding them; apply the same repository policy consistently across all
four sites.
Source: Coding guidelines
| Assert-Contains "deployments\production\.env.example" "hub\.vectorcontrol\.tech/auth/tokendance/callback" "production env example uses Web browser callback as OAuth redirect" | ||
| Assert-Contains "deployments\production\.env.example" "POST /client/auth/oidc/callback" "production env example documents Hub exchange endpoint separately" | ||
| Assert-Contains "deployments\production\.env.example" "http://127\.0\.0\.1/callback" "production env example keeps Desktop/native loopback policy" | ||
| Assert-Contains "deployments\production\docker-compose.yml" "AGENTHUB_TOKENDANCE_ID_REDIRECT_URI: https://hub\.vectorcontrol\.tech/auth/tokendance/callback" "production compose uses Web browser callback as OAuth redirect" | ||
| Assert-Contains "deployments\production\docker-compose.yml" "AGENTHUB_TOKENDANCE_ID_ALLOWED_REDIRECT_URIS: https://hub\.vectorcontrol\.tech/auth/tokendance/callback" "production compose keeps Web callback as the only allowed redirect" | ||
| Assert-Contains "deployments\production\docker-compose.yml" "AGENTHUB_TOKENDANCE_ID_CLIENT_ID: \$\{AGENTHUB_TOKENDANCE_ID_CLIENT_ID:-\}" "production compose exposes OIDC client env overrides" |
There was a problem hiding this comment.
🔒 Security & Privacy | 🟠 Major | ⚡ Quick win
Remove real production server addresses from readiness checks.
These new regex checks commit real production domains. Move concrete production addresses to the external server SSOT, or inject them through protected verification configuration.
As per coding guidelines, “禁止提交 .env、API key、token、cookie、私钥、证书、SSH 配置、真实服务器或内网地址”.
🧰 Tools
🪛 PSScriptAnalyzer (1.25.0)
[info] 183-183: Cmdlet 'Assert-Contains' has positional parameter. Please use named parameters instead of positional parameters when calling a command.
(PSAvoidUsingPositionalParameters)
[info] 184-184: Cmdlet 'Assert-Contains' has positional parameter. Please use named parameters instead of positional parameters when calling a command.
(PSAvoidUsingPositionalParameters)
[info] 185-185: Cmdlet 'Assert-Contains' has positional parameter. Please use named parameters instead of positional parameters when calling a command.
(PSAvoidUsingPositionalParameters)
[info] 186-186: Cmdlet 'Assert-Contains' has positional parameter. Please use named parameters instead of positional parameters when calling a command.
(PSAvoidUsingPositionalParameters)
[info] 187-187: Cmdlet 'Assert-Contains' has positional parameter. Please use named parameters instead of positional parameters when calling a command.
(PSAvoidUsingPositionalParameters)
[info] 188-188: Cmdlet 'Assert-Contains' has positional parameter. Please use named parameters instead of positional parameters when calling a command.
(PSAvoidUsingPositionalParameters)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@scripts/release/verify-web-deploy-readiness.ps1` around lines 183 - 188,
Update the readiness assertions in the verification script to avoid hard-coded
production domains or server addresses. Move the concrete callback and endpoint
values used by these Assert-Contains checks into the external server SSOT or
protected verification configuration, then have the checks reuse those injected
values while preserving validation of the production environment and compose
settings.
Source: Coding guidelines
| # ── 4. Legacy compose inventory closed (PR2) ────────────────────────────── | ||
| # hub-server/deployments/ now holds build inputs only (Dockerfile, | ||
| # docker-entrypoint.sh, README.md). Any compose file there is a legacy | ||
| # resurrection and must FAIL. | ||
| $legacyComposes = @(Get-ChildItem -LiteralPath $LegacyDeployDir -Recurse -Filter "docker-compose*.yml" -File -ErrorAction SilentlyContinue) | ||
| foreach ($legacy in $legacyComposes) { | ||
| $relative = [IO.Path]::GetRelativePath($RepoRootPath, $legacy.FullName).Replace("\", "/") | ||
| $relativeToDeploy = $relative.Substring("hub-server/deployments/".Length) | ||
| if ($LegacyComposeNames -notcontains $relativeToDeploy) { | ||
| Fail-Verifier "unregistered legacy compose appears: $relative (register or migrate in #1527 PR2)" | ||
| } | ||
| } | ||
| if ($legacyComposes.Count -gt 0 -and $script:Failed -eq 0) { | ||
| Pass-Verifier "legacy compose inventory closed ($($legacyComposes.Count) registered file(s))" | ||
| if ($legacyComposes.Count -gt 0) { | ||
| $found = ($legacyComposes | ForEach-Object { [IO.Path]::GetRelativePath($RepoRootPath, $_.FullName).Replace("\", "/") }) -join ", " | ||
| Fail-Verifier "legacy compose inventory closed: compose files must not appear under hub-server/deployments/ (found: $found)" | ||
| } else { | ||
| Pass-Verifier "legacy compose inventory closed (no compose files under hub-server/deployments/)" |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== files =="
git ls-files | rg '(^|/)verify-deployment-shape\.(ps1|Tests\.ps1)$|^scripts/verify/|^scripts/tests/'
echo
echo "== main verifier relevant lines =="
if [ -f scripts/verify/verify-deployment-shape.ps1 ]; then
nl -ba scripts/verify/verify-deployment-shape.ps1 | sed -n '110,145p'
fi
echo
echo "== test relevant lines =="
if [ -f scripts/verify/tests/verify-deployment-shape.Tests.ps1 ]; then
nl -ba scripts/verify/tests/verify-deployment-shape.Tests.ps1 | sed -n '70,125p'
fi
echo
echo "== docker-compose filename patterns in script/tests =="
rg -n 'docker-compose|compose\.|LegacyDeployDir|Get-ChildItem.*-Filter|Filter "docker-compose' scripts/verify/verify-deployment-shale.ps1 scripts/verify/verify-deployment-shape.ps1 scripts/verify/tests/verify-deployment-shape.Tests.ps1 2>/dev/null || true
echo
echo "== PowerShell FileInfo Filter behavior probe using documentation/source grep only? no execute repo =="
python3 - <<'PY'
from pathlib import Path
for p in [Path('scripts/verify/verify-deployment-shape.ps1'), Path('scripts/verify/tests/verify-deployment-shape.Tests.ps1')]:
text = p.read_text()
print(f"\n== {p} mentions docker-compose extensions ==")
for i, line in enumerate(text.splitlines(), 1):
if 'docker-compose' in line:
print(f"{i}: {line}")
PYRepository: TokenDanceLab/AgentHub
Length of output: 3307
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== script relevant lines =="
if [ -f scripts/verify/verify-deployment-shape.ps1 ]; then
sed -n '115,145p' scripts/verify/verify-deployment-shape.ps1
fi
echo
echo "== test relevant lines =="
if [ -f scripts/verify/tests/verify-deployment-shape.Tests.ps1 ]; then
sed -n '85,120p' scripts/verify/tests/verify-deployment-shape.Tests.ps1
fi
echo
echo "== compose filename patterns =="
rg -n 'docker-compose|\.yml|\.yaml|LegacyDeployDir' scripts/verify/verify-deployment-shape.ps1 scripts/verify/tests/verify-deployment-shape.Tests.ps1 2>/dev/null || trueRepository: TokenDanceLab/AgentHub
Length of output: 4972
🌐 Web query:
PowerShell Get-ChildItem -Filter wildcard matches *.yml does not match *.yaml case insensitive
💡 Result:
In PowerShell, the wildcard pattern .yml specifically matches files ending with the.yml extension and does not match files with the.yaml extension [1][2]. This behavior occurs because PowerShell wildcards perform a character-by-character pattern match rather than a semantic match for file extensions [1]. The asterisk () character represents any number of characters, but it must be followed by the exact literal sequence provided in your pattern [1]. To match both.yml and.yaml files, you should use one of the following methods: 1. Using the -Include parameter: This is often the most readable way to specify multiple patterns [2]. Get-ChildItem -Path. -Include *.yml, *.yaml 2. Using a regex-based filter with Where-Object: This offers the most precise control if you need to perform complex matching. Get-ChildItem -File | Where-Object {
Citations:
- 1: https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_wildcards?view=powershell-7.6
- 2: https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.management/get-childitem?view=powershell-7.6
- 3: https://ss64.com/ps/syntax-wildcards.html
Close the .yaml compose-file bypass.
docker-compose*.yml does not match Compose files ending in .yaml, so a legacy .yaml compose file under hub-server/deployments/ is not flagged by the closed-inventory rule.
- Update
scripts/verify/verify-deployment-shape.ps1to include.yamlcompose filenames for the legacy legacy compose path. - Add a
.yamlresurrection fixture inscripts/verify/tests/verify-deployment-shape.Tests.ps1and assert the samelegacy compose inventory closedfailure reason.
🧰 Tools
🪛 PSScriptAnalyzer (1.25.0)
[warning] Missing BOM encoding for non-ASCII encoded file 'verify-deployment-shape.ps1'
(PSUseBOMForUnicodeEncodedFile)
📍 Affects 2 files
scripts/verify/verify-deployment-shape.ps1#L127-L136(this comment)scripts/verify/tests/verify-deployment-shape.Tests.ps1#L94-L110
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@scripts/verify/verify-deployment-shape.ps1` around lines 127 - 136, The
legacy compose inventory check in Get-ChildItem must detect both .yml and .yaml
compose filenames under the legacy deployment directory. Update
scripts/verify/verify-deployment-shape.ps1 lines 127-136 accordingly, and add a
.yaml resurrection fixture plus an assertion for the same “legacy compose
inventory closed” failure reason in
scripts/verify/tests/verify-deployment-shape.Tests.ps1 lines 94-110.
…1590) #1527 PR1(94a2644f)已确立 deployments/production/docker-compose.yml 为权威 production compose SSOT 并挂 verify-deployment-shape 门禁;本 PR 完成 PR2 收口: - 删除 hub-server/deployments 下旧独立 PG+Redis 拓扑资产:docker-compose.prod.yml、 docker-compose.us1.yml、hk2/(compose + deploy-hk2.sh + deploy-web-hk2.sh + nginx/env 模板)、deploy.sh、Caddyfile/Caddyfile.prod、.env.production.example、 backup-cron、.dockerignore(构建上下文为仓库根,消费根 .dockerignore)。 - 保留构建输入:Dockerfile、docker-entrypoint.sh(Dockerfile COPY 依赖); README.md 精简为构建输入说明(verify-doc-ssot 要求保留 "Live host" marker)。 - verify-deployment-shape.ps1 遗留清单由"注册制"改为"关闭态": hub-server/deployments/ 下出现任何 compose 文件即 FAIL;自测 5/5 通过, 含"新增第二份手维护 production compose 必 FAIL"回归。 - cd-pr-check.yml 移除 deploy.sh / .env.production.example 检查与 deploy.sh 结构校验 step;cd-production.yml 部署/回滚/health-check 指引回显全部改指 deployments/production/docker-compose.yml(仅引用同步,未动行为/权限/secrets)。 - verify-web-deploy-readiness.ps1 生产 OIDC 断言改指权威 compose + 权威 .env.example(env 模板补 OIDC 回调/交换端点/loopback 说明段)。 - docs/architecture/05-deployment.md inventory 表更新为最终形态。 未删 Dockerfile,未触碰 checks.yml / release.yml / cd-hub-server.yml, 未修改真实服务器/secret/生产部署。 Co-authored-by: Codex <codex@vectorcontrol.tech>
背景
#1527 PR1(cfde8494)确立
deployments/production/docker-compose.yml为唯一权威 production compose,并挂verify-deployment-shape.ps1门禁(遗留清单注册制 + "新增第二份手维护 production compose 必 FAIL"机器证明)。本 PR(PR2)完成 legacy compose/脚本收口与cd-production.yml引用同步。Compose normalized 差异表(docker compose v5.3.1 config --format json,本机可用)
对比对象:权威
deployments/production/docker-compose.ymlvs legacy 三份(docker-compose.prod.yml/docker-compose.us1.yml/hk2/docker-compose.hk2.yml)。${PG_HOST}:5433+sslmode=require(host/Azure PG 直连)postgres:5432(compose 内 PG)127.0.0.1:6380:6379结论:legacy 三份是同一套废弃的"独立 PG+Redis"拓扑(三份之间仅 CORS 列表、ALLOWED_REDIRECT_URIS loopback、redis healthcheck 微差),与权威模板(host/Azure PG 直连 + 轻量本地 redis)是拓扑级差异,不是 region 变体。server SSOT(
projects/agenthub/STATE.md)确认 live 仅 hk3、us1 仅冷备、hk2 无记录。因此直接删除,不建 override:override 会复活废弃拓扑,且会触发 verify-deployment-shape"第二份手维护 production compose 必 FAIL"负向用例。最终形态
删除(14 个文件 / hk2 目录整体)
hub-server/deployments/docker-compose.prod.yml、docker-compose.us1.yml、hk2/docker-compose.hk2.ymlhub-server/deployments/deploy.sh、hk2/deploy-hk2.sh、hk2/deploy-web-hk2.sh(纯人工运维胶水,运维由 server SSOT 覆盖)hub-server/deployments/Caddyfile、Caddyfile.prod、.env.production.example、backup-cron、.dockerignore(构建上下文为仓库根)hk2/.env.example、hk2/nginx-hk2-v2.conf、hk2/nginx-hk2.conf保留
hub-server/deployments/Dockerfile(构建输入,cd-hub-server/cd-production 消费,未改动)hub-server/deployments/docker-entrypoint.sh(构建输入,Dockerfile COPY 依赖,未改动)hub-server/deployments/README.md(精简为构建输入说明;verify-doc-ssot 要求该文件存在)docker-compose.yml(local-development shape,任务书明确不删)无新增 override 文件。
引用变更清单
scripts/verify/verify-deployment-shape.ps1hub-server/deployments/下出现任何 compose 即 FAILscripts/verify/tests/verify-deployment-shape.Tests.ps1.github/workflows/cd-pr-check.yml.github/workflows/cd-production.ymldeployments/production/docker-compose.yml(仅引用同步,未动行为/权限/secrets)scripts/release/verify-web-deploy-readiness.ps1.env.example(env 模板补 OIDC 回调/交换端点/loopback 说明段,语义对齐权威 compose:ALLOWED_REDIRECT_URIS 固定 Web 回调)deployments/production/.env.exampledocs/architecture/05-deployment.md未修改:
.github/workflows/checks.yml、release.yml、cd-hub-server.yml(任务书禁止)。负向证明
verify-deployment-shape.Tests.ps1负例 1 通过 —— 在 fixture 的deployments/production/下新增docker-compose.us2.yml时 verifier 以"second hand-maintained production compose"理由退出非零。hub-server/deployments/下新增任何 compose 文件即 FAIL(关闭态)。rg全仓(排除 docs/archives、docs/archive 冻结历史)仅命中docs/architecture/05-deployment.md一处 —— 即本 PR 的 inventory 表(以"已删除"标注的最终形态记录,非活引用)。config解析成功(exit 0);本 PR 后仓库内唯一生产 compose 为权威模板。范围声明
hub-server/deployments/Dockerfile(构建输入,构建消费者真实存在)。本地验证输出摘要
docker compose config(权威)→ exit 0verify-deployment-shape.ps1→ PASS 4/4verify-deployment-shape.Tests.ps1→ 5/5 PASSverify-ci-gates.ps1→ ok;verify-doc-ssot.ps1→ okgit diff --check→ 干净bash -n hub-server/deployments/docker-entrypoint.sh→ 通过Summary by CodeRabbit
Deployment
Verification