Skip to content

Commit 85d1d81

Browse files
committed
docs: add container TLS, network ecosystem, and MCP diagnostics guidance
- Add CA cert mount pattern for scratch/distroless container images - Document ecosystem identifiers vs custom domains (strict: false) - Add npx/uvx package registry access requirements - Add MCP gateway log diagnostics to debugging checklist - Add entrypointArgs and mounts fields to MCP server schema - Add critical rules #13-#16 for container TLS, strict mode, ecosystems, MCP logs
1 parent b689cd4 commit 85d1d81

4 files changed

Lines changed: 100 additions & 1 deletion

File tree

skills/aw-author/SKILL.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -383,3 +383,7 @@ These rules apply across ALL modes:
383383
10. **`read-all` permission shorthand** expands to read on all permission scopes
384384
11. **`event.json` fallback** — when `${{ github.event }}` is unavailable, agents should check for `event.json` in the workspace
385385
12. **Container-based MCP servers from `ghcr.io` require a GHCR login step** — add a `steps:` block with `docker login ghcr.io` using `${{ github.token }}` before `safe-outputs:`, or container pulls fail silently
386+
13. **Minimal/scratch Docker images have no CA certificates** — if a container-based MCP server uses `FROM scratch` or a distroless base, mount host certs with `mounts: ["/etc/ssl/certs:/etc/ssl/certs:ro"]` and set `SSL_CERT_FILE: "/etc/ssl/certs/ca-certificates.crt"` in `env:`, or TLS calls fail with "certificate verify failed"
387+
14. **`strict: false` is also required for custom API domains** — ecosystem identifiers (`defaults`, `github`, `containers`, `node`, `python`) work in strict mode, but custom domains like `*.datadoghq.com` require `strict: false`
388+
15. **Add `node` and `python` ecosystems** when MCP servers use `npx` or `uvx` — these ecosystems allow package registry access (npm, PyPI) needed for process-based MCP servers
389+
16. **MCP gateway logs are the primary debug source** — when MCP tool calls return vague errors (e.g., "no data found"), download `agent-artifacts/mcp-logs/{server}.log` from the workflow run to see the real error (TLS failures, auth errors, timeouts)

skills/aw-author/references/frontmatter-schema.md

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -238,6 +238,32 @@ network:
238238
- Use `network: true` for unrestricted (discouraged)
239239
- Prefer explicit domain allowlists
240240

241+
### Ecosystem Identifiers vs Custom Domains
242+
243+
Ecosystem identifiers work in strict mode (`strict: true`, the default):
244+
- `defaults` — standard GitHub/Actions infrastructure
245+
- `github` — GitHub API and related domains
246+
- `containers` — Docker Hub, GHCR (`ghcr.io`), Quay
247+
- `node` — npm registries (needed for `npx`-based MCP servers)
248+
- `python` — PyPI (needed for `uvx`-based MCP servers)
249+
250+
**Custom domains require `strict: false`.** Any domain not covered by an ecosystem identifier (e.g., `*.datadoghq.com`, `api.pagerduty.com`, `*.atlassian.net`) requires setting `strict: false` at the frontmatter root level, or the compiler rejects it.
251+
252+
```yaml
253+
strict: false
254+
255+
network:
256+
firewall:
257+
allowed:
258+
- defaults
259+
- github
260+
- containers
261+
- node
262+
- python
263+
- "*.datadoghq.com"
264+
- "api.pagerduty.com"
265+
```
266+
241267
## Imports (`imports:`)
242268

243269
```yaml
@@ -263,6 +289,28 @@ mcp-servers:
263289
allowed: ["tool_name"]
264290
```
265291

292+
### Container-Based MCP Servers
293+
294+
```yaml
295+
mcp-servers:
296+
server-name:
297+
container: "ghcr.io/org/image:tag"
298+
entrypointArgs:
299+
- "subcommand"
300+
env:
301+
API_KEY: "${{ secrets.VALUE }}"
302+
SSL_CERT_FILE: "/etc/ssl/certs/ca-certificates.crt"
303+
mounts:
304+
- "/etc/ssl/certs:/etc/ssl/certs:ro"
305+
```
306+
307+
| Field | Type | Description |
308+
|-------|------|-------------|
309+
| `entrypointArgs` | list | Arguments passed to the container's ENTRYPOINT |
310+
| `mounts` | list | Volume mounts in `"host:container:mode"` format |
311+
312+
**CA Certificate Warning:** Containers built from `FROM scratch` or distroless base images have no CA certificate bundle. Without CA certs, all TLS connections fail with "certificate verify failed". Mount the host's CA certs read-only and set `SSL_CERT_FILE` to point to them.
313+
266314
## Complete Example
267315

268316
```yaml

skills/aw-author/references/tools-reference.md

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -252,10 +252,12 @@ mcp-servers:
252252
| `command` | string | Executable path (process-based) |
253253
| `args` | list | Command arguments |
254254
| `container` | string | Docker image reference (alternative to command) |
255+
| `entrypointArgs` | list | Arguments passed to container ENTRYPOINT |
255256
| `url` | string | HTTP endpoint (alternative to command) |
256257
| `headers` | mapping | HTTP headers for url-based servers |
257258
| `registry` | string | MCP registry URI (informational only, does not affect execution) |
258259
| `env` | mapping | Environment variables |
260+
| `mounts` | list | Volume mounts in `"host:container:mode"` format |
259261
| `allowed` | list | Tool name restrictions |
260262

261263
### Execution Modes
@@ -296,6 +298,30 @@ steps:
296298

297299
This applies to **all** container-based MCP servers pulling from `ghcr.io`, regardless of whether the image is public or private. The `github.token` is automatically available and has sufficient scope for package reads.
298300

301+
### CA Certificates for Minimal Images
302+
303+
Containers built from `FROM scratch` or distroless base images have **no CA certificate bundle**. Any TLS connection (HTTPS API calls) will fail with "certificate verify failed". The MCP tool may return a misleading error (e.g., "no data found") instead of the real TLS error — check `agent-artifacts/mcp-logs/{server}.log` for the actual failure.
304+
305+
**Fix:** Mount the host runner's CA certs and set `SSL_CERT_FILE`:
306+
307+
```yaml
308+
mcp-servers:
309+
my-server:
310+
container: ghcr.io/org/image:latest
311+
env:
312+
SSL_CERT_FILE: "/etc/ssl/certs/ca-certificates.crt"
313+
mounts:
314+
- "/etc/ssl/certs:/etc/ssl/certs:ro"
315+
```
316+
317+
### Package Registry Access for Process-Based Servers
318+
319+
Process-based MCP servers using `npx` or `uvx` need package registry access at runtime:
320+
- **`npx` servers** — add `node` to `network.firewall.allowed` (covers npm registries)
321+
- **`uvx` servers** — add `python` to `network.firewall.allowed` (covers PyPI)
322+
323+
These ecosystem identifiers work in strict mode and do not require `strict: false`.
324+
299325
### Key Constraints
300326

301327
- Tool declarations merge from imported components

skills/aw-author/references/validation.md

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,10 @@ Occur during GitHub Actions execution.
5050
- **Network blocked:** External URL access when no `network` configuration
5151
- **MCP server connection failed:** Server not available, wrong args, missing env vars
5252
- **Container pull failed (silent):** Container-based MCP servers from `ghcr.io` fail silently if no GHCR login step is present. Add a `steps:` block with `docker login ghcr.io` using `${{ github.token }}`
53+
- **TLS certificate verify failed:** Container-based MCP servers built from `FROM scratch` or distroless images have no CA certificate bundle. Mount host certs: `mounts: ["/etc/ssl/certs:/etc/ssl/certs:ro"]` and set `SSL_CERT_FILE: "/etc/ssl/certs/ca-certificates.crt"` in `env:`
54+
- **MCP server registers no tools (`tools: None`):** Server started but returned empty tool list — usually caused by an init-time API call failure (check MCP gateway logs for auth errors or TLS failures)
55+
- **Misleading tool error messages:** MCP tool errors like "no data found" may mask underlying TLS, auth, or network failures — always check `agent-artifacts/mcp-logs/{server}.log` for the real error
56+
- **Firewall blocking MCP traffic:** If firewall logs show only `api.openai.com` with no other domains, the MCP containers' API calls are being blocked — add the required API domains to `network.firewall.allowed` with `strict: false`
5357

5458
### Permission Errors
5559
- **Token insufficient:** `GITHUB_TOKEN` lacks required scope
@@ -116,6 +120,9 @@ The workflow runs but produces incorrect or unexpected results.
116120
| Overlapping triggers | Double-processing | Use distinct event types |
117121
| `container:` with non-Docker value | Compilation error | Use valid Docker image reference |
118122
| `container: ghcr.io/…` without GHCR login step | Silent runtime failure | Add `steps:` with `docker login ghcr.io` |
123+
| `container:` from scratch/distroless without CA certs | TLS calls fail silently | Add `mounts` + `SSL_CERT_FILE` env |
124+
| Custom API domains without `strict: false` | Compiler rejects non-ecosystem domains | Set `strict: false` in frontmatter |
125+
| Missing `node`/`python` ecosystem for npx/uvx MCP servers | Package install fails at runtime | Add `node`/`python` to network allowed |
119126

120127
### Prose Anti-Patterns
121128

@@ -167,8 +174,22 @@ When a workflow fails, check in this order:
167174
- [ ] Edge cases handled
168175
- [ ] Output format matches safe-output types
169176

170-
### 6. Runtime
177+
### 6. Network & TLS
178+
- [ ] Custom API domains (e.g., `*.datadoghq.com`) present in `network.firewall.allowed`
179+
- [ ] `strict: false` set if custom domains are used (ecosystem identifiers like `defaults`, `github`, `containers`, `node`, `python` work in strict mode; custom domains do not)
180+
- [ ] `node` ecosystem included if MCP servers use `npx` (for npm registry access)
181+
- [ ] `python` ecosystem included if MCP servers use `uvx` (for PyPI access)
182+
- [ ] Container-based MCP servers from minimal/scratch images have CA cert mounts (`mounts: ["/etc/ssl/certs:/etc/ssl/certs:ro"]` + `SSL_CERT_FILE` env var)
183+
184+
### 7. Runtime
171185
- [ ] Timeout sufficient for task complexity
172186
- [ ] Engine configured correctly (API key secret present)
173187
- [ ] No circular imports
174188
- [ ] No conflicting workflows on same trigger
189+
190+
### 8. MCP Server Diagnostics
191+
- [ ] Download `agent-artifacts/mcp-logs/{server}.log` from workflow run to see real errors (tool error messages can be misleading)
192+
- [ ] Check firewall logs — if only `api.openai.com` appears with no other domains, MCP containers are not reaching external APIs
193+
- [ ] Look for `tools: None` in MCP capability announcements — indicates the server started but registered no tools (likely an auth or init failure)
194+
- [ ] Check for silent secret failures — missing or empty `COPILOT_MCP_` secrets cause MCP servers to start but fail on first API call
195+
- [ ] Verify `SSL_CERT_FILE` env var is set for containers that mount host CA certs

0 commit comments

Comments
 (0)