@axinom/mosaic-agent-skills 0.4.0 → 0.4.1
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.
- package/package.json +2 -2
- package/skills/deploy-service/SKILL.md +103 -0
- package/skills/deploy-service/refs/build-and-push-image.md +55 -0
- package/skills/deploy-service/refs/build-and-register-pilet.md +54 -0
- package/skills/deploy-service/refs/credentials-and-setup.md +88 -0
- package/skills/deploy-service/refs/deploy-and-monitor.md +76 -0
- package/skills/deploy-service/refs/manifest-review-and-upload.md +63 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@axinom/mosaic-agent-skills",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.1",
|
|
4
4
|
"description": "MCP server bundled with Mosaic development skills and tools for AI agents",
|
|
5
5
|
"bin": "./dist/index.js",
|
|
6
6
|
"files": [
|
|
@@ -36,5 +36,5 @@
|
|
|
36
36
|
"publishConfig": {
|
|
37
37
|
"access": "public"
|
|
38
38
|
},
|
|
39
|
-
"gitHead": "
|
|
39
|
+
"gitHead": "8e28563eaafe8791244c3eebdb9da64b8e400c0c"
|
|
40
40
|
}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: deploy-service
|
|
3
|
+
description: |
|
|
4
|
+
Deploys a custom service from a Mosaic monorepo to the Axinom Mosaic
|
|
5
|
+
Hosting Service. Covers the full lifecycle: authenticating, discovering
|
|
6
|
+
deployable services, verifying one-time prerequisites (container registry,
|
|
7
|
+
service definition), building and pushing a Docker image, optionally
|
|
8
|
+
building and registering a microfrontend pilet, uploading a deployment
|
|
9
|
+
manifest, initiating a rolling deployment, and monitoring status with
|
|
10
|
+
log-based error diagnosis.
|
|
11
|
+
|
|
12
|
+
Use this skill whenever the user wants to deploy, redeploy, or release a
|
|
13
|
+
service to the Mosaic Hosting Service — including first-time deployments,
|
|
14
|
+
updating a running service, or recovering from a failed deployment.
|
|
15
|
+
allowed-tools:
|
|
16
|
+
- list_skills
|
|
17
|
+
- get_skill
|
|
18
|
+
- get_skill_references
|
|
19
|
+
- execute_skill
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
# Deploy Service to Mosaic Hosting
|
|
23
|
+
|
|
24
|
+
## Input
|
|
25
|
+
|
|
26
|
+
Service name or ID (e.g. "media", "media-service"). If omitted, discover
|
|
27
|
+
and ask.
|
|
28
|
+
|
|
29
|
+
## Overview
|
|
30
|
+
|
|
31
|
+
Each deployment is a tuple of: container image + deployment manifest +
|
|
32
|
+
optional pilet (only for services with a `workflows/` folder). Deployments
|
|
33
|
+
are additive — each supersedes the previous; reusing an existing image,
|
|
34
|
+
pilet, or manifest in a new deployment is always valid.
|
|
35
|
+
|
|
36
|
+
### API vs CLI
|
|
37
|
+
|
|
38
|
+
| Action | Use |
|
|
39
|
+
|--------|-----|
|
|
40
|
+
| Auth token, registry/service-definition check & create | API |
|
|
41
|
+
| Docker build & push | shell |
|
|
42
|
+
| Pilet build, pack & register | CLI (file upload) |
|
|
43
|
+
| Manifest upload | CLI — preserves `${__ax_hosted__.dynamic.%}` secret injection |
|
|
44
|
+
| Deployment initiation | CLI — name-based, no UUID lookups |
|
|
45
|
+
| Status polling, log fetching, DNS endpoints | API |
|
|
46
|
+
|
|
47
|
+
Retrieve all reference files with `get_skill_references` before starting.
|
|
48
|
+
For API calls, use Node.js with `--input-type=commonjs` to avoid ESM/CJS
|
|
49
|
+
conflicts. Pattern:
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
node --input-type=commonjs <<'EOF'
|
|
53
|
+
const https = require('https');
|
|
54
|
+
const fs = require('fs');
|
|
55
|
+
// ... make request, write result to file
|
|
56
|
+
EOF
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Save the token to `.jwt` and reuse it.
|
|
60
|
+
|
|
61
|
+
## Steps
|
|
62
|
+
|
|
63
|
+
### 0. Authenticate → `refs/credentials-and-setup.md`
|
|
64
|
+
|
|
65
|
+
Read credentials from root `.env`, obtain a token, save to `.jwt`.
|
|
66
|
+
|
|
67
|
+
### 1. Discover & Select Service
|
|
68
|
+
|
|
69
|
+
Scan `services/*/service/mosaic-hosting-deployment-manifest.yaml`. For each,
|
|
70
|
+
read `serviceId` from the YAML and note whether a sibling `workflows/` folder
|
|
71
|
+
exists (`hasWorkflows`).
|
|
72
|
+
|
|
73
|
+
Ask the user to choose if not already specified.
|
|
74
|
+
|
|
75
|
+
### 2. Prerequisites → `refs/credentials-and-setup.md`
|
|
76
|
+
|
|
77
|
+
Check (and create if missing) the container registry connection and service
|
|
78
|
+
definition via API. Both are one-time per environment/service.
|
|
79
|
+
|
|
80
|
+
### 3. Backend Image → `refs/build-and-push-image.md`
|
|
81
|
+
|
|
82
|
+
*Does the backend need updating?* Yes → build & push, get `imageTag`.
|
|
83
|
+
No → ask for the existing tag to reuse.
|
|
84
|
+
|
|
85
|
+
### 4. Pilet (skip if `hasWorkflows` is false) → `refs/build-and-register-pilet.md`
|
|
86
|
+
|
|
87
|
+
*Does the frontend need updating?* Yes → build, pack & register via CLI.
|
|
88
|
+
No → confirm the existing `piletRef` to reuse.
|
|
89
|
+
|
|
90
|
+
### 5. Manifest → `refs/manifest-review-and-upload.md`
|
|
91
|
+
|
|
92
|
+
Ask if any manifest changes are needed. If changes are required, review and
|
|
93
|
+
upload a new named manifest. If the manifest is unchanged, the user may select
|
|
94
|
+
an existing one and skip the upload — each deployment just needs a valid
|
|
95
|
+
`manifestName`, whether new or reused.
|
|
96
|
+
|
|
97
|
+
### 6. Deploy & Monitor → `refs/deploy-and-monitor.md`
|
|
98
|
+
|
|
99
|
+
Initiate via CLI, parse `serviceDeploymentId` from the output, poll status
|
|
100
|
+
via API. On `READY` show DNS endpoints. On `CREATE_ERROR` fetch logs,
|
|
101
|
+
diagnose, and either fix the manifest and redeploy, or hand off to the user.
|
|
102
|
+
|
|
103
|
+
Once the deployment resolves (success or terminal error), delete `.jwt`.
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: build-and-push-image
|
|
3
|
+
input:
|
|
4
|
+
- registryHost, repositoryName (from service definition)
|
|
5
|
+
- servicePath (e.g. services/media/service)
|
|
6
|
+
- buildScript (e.g. build:media-service:prod)
|
|
7
|
+
output:
|
|
8
|
+
- imageTag (YYYYMMDD.N — passed as -t to the deploy command)
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
# Build & Push Container Image
|
|
12
|
+
|
|
13
|
+
## Existing Images
|
|
14
|
+
|
|
15
|
+
`repositoryTags` on the service definition lists all pushed images, sorted
|
|
16
|
+
newest first (tags are `YYYYMMDD.N`, so alpha order = chronological):
|
|
17
|
+
|
|
18
|
+
```graphql
|
|
19
|
+
# POST {HOSTING_SERVICE_BASE_URL}/graphql
|
|
20
|
+
query {
|
|
21
|
+
serviceDefinitions(condition: { serviceId: "{serviceId}" }) {
|
|
22
|
+
nodes {
|
|
23
|
+
repositoryTags { fullyQualifiedImageName containerImageVersion }
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Present as a numbered list (newest first) with `[0] Build & push a new image` as the last option. Wait for the user to pick by number — never ask them to type a tag manually.
|
|
30
|
+
|
|
31
|
+
## Build & Push
|
|
32
|
+
|
|
33
|
+
Check Docker login: `docker info` (look for `Username:`). If not logged in:
|
|
34
|
+
```bash
|
|
35
|
+
docker login {registryHost}
|
|
36
|
+
```
|
|
37
|
+
Fallback: check `~/.docker/config.json` or `~/snap/docker/current/.docker/config.json`.
|
|
38
|
+
|
|
39
|
+
Dockerfile is typically at the repo root. If not, search and confirm with the user.
|
|
40
|
+
|
|
41
|
+
Tag pattern: `YYYYMMDD.N` (e.g. `20260423.1`, increment `.N` for same-day builds).
|
|
42
|
+
The Hosting Service appends this to `{registryHost}/{repositoryName}:` — pass only
|
|
43
|
+
the date+index as `-t` to the deploy command, not the full reference.
|
|
44
|
+
|
|
45
|
+
Run from **repo root**:
|
|
46
|
+
```bash
|
|
47
|
+
docker build \
|
|
48
|
+
-t {registryHost}/{repositoryName}:{imageTag} \
|
|
49
|
+
--build-arg PACKAGE_ROOT={servicePath} \
|
|
50
|
+
--build-arg PACKAGE_BUILD_COMMAND={buildScript} \
|
|
51
|
+
--platform linux/amd64 \
|
|
52
|
+
.
|
|
53
|
+
|
|
54
|
+
docker push {registryHost}/{repositoryName}:{imageTag}
|
|
55
|
+
```
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: build-and-register-pilet
|
|
3
|
+
input:
|
|
4
|
+
- serviceId
|
|
5
|
+
- workflowsPath (e.g. services/media/workflows)
|
|
6
|
+
output:
|
|
7
|
+
- piletRef = {piletName}@{piletVersion} (passed as -p to the deploy command)
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# Build & Register Pilet
|
|
11
|
+
|
|
12
|
+
## Existing Pilets
|
|
13
|
+
|
|
14
|
+
```graphql
|
|
15
|
+
# POST {HOSTING_SERVICE_BASE_URL}/graphql
|
|
16
|
+
query {
|
|
17
|
+
servicePiletArtifacts(
|
|
18
|
+
filter: { serviceId: { equalTo: "{serviceId}" } }
|
|
19
|
+
orderBy: CREATED_DATE_DESC
|
|
20
|
+
first: 5
|
|
21
|
+
) {
|
|
22
|
+
nodes { name packageVersion createdDate }
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
Present results as a numbered list (`{name}@{packageVersion}`, newest first) with `[0] Build & register a new pilet` as the last option. Wait for the user to pick by number. The chosen value is passed as `-p` to the deploy command.
|
|
28
|
+
|
|
29
|
+
## Build & Register
|
|
30
|
+
|
|
31
|
+
Read `name` and `version` from `{workflowsPath}/package.json` — these form
|
|
32
|
+
the pilet reference `{piletName}@{piletVersion}` used in the deploy command.
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
cd {workflowsPath} && yarn build && yarn pilet pack
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
Locate the produced `.tgz`:
|
|
39
|
+
```bash
|
|
40
|
+
find {workflowsPath} -maxdepth 1 -name "*.tgz"
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
Use the path returned by `find` directly as `{tgzPath}`.
|
|
44
|
+
|
|
45
|
+
If `{piletName}@{piletVersion}` already appears in the existing pilets list,
|
|
46
|
+
warn the user that it will be overwritten and ask for confirmation before proceeding.
|
|
47
|
+
|
|
48
|
+
Register (requires `MICRO_FRONTEND_SERVICE_BASE_URL` in root `.env`):
|
|
49
|
+
```bash
|
|
50
|
+
yarn util:load-vars mosaic hosting pilet register \
|
|
51
|
+
-i {serviceId} \
|
|
52
|
+
-p {tgzPath} \
|
|
53
|
+
--overrideRegistration
|
|
54
|
+
```
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: credentials-and-setup
|
|
3
|
+
input:
|
|
4
|
+
- serviceId
|
|
5
|
+
- root .env (MOSAIC_HOSTING_CLIENT_ID, MOSAIC_HOSTING_CLIENT_SECRET, ID_SERVICE_AUTH_BASE_URL, HOSTING_SERVICE_BASE_URL)
|
|
6
|
+
output:
|
|
7
|
+
- access token in .jwt
|
|
8
|
+
- registryHost, registryUsername confirmed
|
|
9
|
+
- serviceDefinitionId, repositoryName confirmed
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
# Credentials & Prerequisites
|
|
13
|
+
|
|
14
|
+
## Token
|
|
15
|
+
|
|
16
|
+
If `MOSAIC_HOSTING_CLIENT_ID` or `MOSAIC_HOSTING_CLIENT_SECRET` are missing
|
|
17
|
+
from root `.env`, check whether a setup script exists:
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
# Check for a hosting setup script (name may vary per repo)
|
|
21
|
+
grep -r "setup.*hosting\|hosting.*setup" package.json scripts/ 2>/dev/null | head -5
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
If a setup script is found (e.g. `yarn setup:hosting`), run it. It typically
|
|
25
|
+
requires `DEV_SERVICE_ACCOUNT_CLIENT_ID` and `DEV_SERVICE_ACCOUNT_CLIENT_SECRET`
|
|
26
|
+
to already be in `.env` — if those are also missing, stop and ask the user.
|
|
27
|
+
|
|
28
|
+
If no setup script exists, ask the user to provide `MOSAIC_HOSTING_CLIENT_ID`
|
|
29
|
+
and `MOSAIC_HOSTING_CLIENT_SECRET` directly and add them to `.env`.
|
|
30
|
+
|
|
31
|
+
```graphql
|
|
32
|
+
# POST {ID_SERVICE_AUTH_BASE_URL}/graphql (no auth required)
|
|
33
|
+
mutation {
|
|
34
|
+
authenticateServiceAccount(input: {
|
|
35
|
+
clientId: "{MOSAIC_HOSTING_CLIENT_ID}"
|
|
36
|
+
clientSecret: "{MOSAIC_HOSTING_CLIENT_SECRET}"
|
|
37
|
+
}) { accessToken }
|
|
38
|
+
}
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
Save `accessToken` to `.jwt`. All subsequent calls use
|
|
42
|
+
`Authorization: Bearer {token}`. On 401, re-fetch and overwrite.
|
|
43
|
+
|
|
44
|
+
## Container Registry
|
|
45
|
+
|
|
46
|
+
The Hosting Service constructs image references as
|
|
47
|
+
`{registryHost}/{repositoryName}:{imageTag}`.
|
|
48
|
+
|
|
49
|
+
```graphql
|
|
50
|
+
# POST {HOSTING_SERVICE_BASE_URL}/graphql
|
|
51
|
+
{ containerRegistryConnections { nodes { id host username } } }
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
If connections exist, confirm which one with the user. If none, ask for
|
|
55
|
+
host/username/password then:
|
|
56
|
+
|
|
57
|
+
```graphql
|
|
58
|
+
mutation {
|
|
59
|
+
createContainerRegistryConnection(input: {
|
|
60
|
+
containerRegistryConnection: { host: "...", username: "...", password: "..." }
|
|
61
|
+
}) { containerRegistryConnection { id host username } }
|
|
62
|
+
}
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
## Service Definition
|
|
66
|
+
|
|
67
|
+
```graphql
|
|
68
|
+
{ serviceDefinitions(condition: { serviceId: "{serviceId}" }) {
|
|
69
|
+
nodes { id serviceId repositoryName activeDeploymentStatus }
|
|
70
|
+
} }
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
If found, proceed. If not, suggest `{registryUsername}/{serviceId}` as
|
|
74
|
+
`repositoryName`, confirm with user, then:
|
|
75
|
+
|
|
76
|
+
```graphql
|
|
77
|
+
mutation {
|
|
78
|
+
createServiceDefinition(input: {
|
|
79
|
+
serviceDefinition: {
|
|
80
|
+
serviceId: "{serviceId}"
|
|
81
|
+
name: "{serviceId}"
|
|
82
|
+
repositoryName: "{registryUsername}/{serviceId}"
|
|
83
|
+
}
|
|
84
|
+
}) { serviceDefinition { id repositoryName } }
|
|
85
|
+
}
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
> Avoid `ax-` or `axinom-` prefixes in serviceId — reserved for Axinom Owned services.
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: deploy-and-monitor
|
|
3
|
+
input:
|
|
4
|
+
- serviceId, imageTag, manifestName, piletRef = {piletName}@{piletVersion} (optional)
|
|
5
|
+
- HOSTING_SERVICE_BASE_URL + token from .jwt
|
|
6
|
+
output:
|
|
7
|
+
- serviceDeploymentId, status, DNS endpoints
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# Deploy & Monitor
|
|
11
|
+
|
|
12
|
+
## Initiate via CLI
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
# with pilet
|
|
16
|
+
yarn util:load-vars mosaic hosting service deploy \
|
|
17
|
+
-i {serviceId} -t {imageTag} -p {piletRef} \
|
|
18
|
+
-m {manifestName} -n {serviceId}-deployment-{YYYYMMDD}.N
|
|
19
|
+
|
|
20
|
+
# without pilet
|
|
21
|
+
yarn util:load-vars mosaic hosting service deploy \
|
|
22
|
+
-i {serviceId} -t {imageTag} \
|
|
23
|
+
-m {manifestName} -n {serviceId}-deployment-{YYYYMMDD}.N
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
Use today's date for the deployment name. Increment `.N` if multiple deployments are made on the same day.
|
|
27
|
+
|
|
28
|
+
The CLI prints human-readable status lines followed by a JSON object. Extract the
|
|
29
|
+
JSON by finding the line that starts with `{` and parse `serviceDeploymentId` from it:
|
|
30
|
+
```json
|
|
31
|
+
{"serviceDeploymentId":"<uuid>","name":"...","status":"CREATE_PENDING"}
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
Use this ID for all subsequent queries. Do not query by `last: 1` ordering —
|
|
35
|
+
stale failed deployments from prior runs can appear ahead of the new one.
|
|
36
|
+
|
|
37
|
+
## Poll Status
|
|
38
|
+
|
|
39
|
+
Poll every ~15s until status is no longer `CREATE_PENDING`:
|
|
40
|
+
|
|
41
|
+
```graphql
|
|
42
|
+
# POST {HOSTING_SERVICE_BASE_URL}/graphql
|
|
43
|
+
query($id: UUID!) {
|
|
44
|
+
serviceDeployment(id: $id) {
|
|
45
|
+
status
|
|
46
|
+
errorMessage
|
|
47
|
+
dnsRecords { nodes { configRefName fqdn } }
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
# variables: {"id": "{serviceDeploymentId}"}
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
**`READY`** — show DNS endpoints (each `configRefName` maps to a port in
|
|
54
|
+
`dnsMappedPorts` in the manifest):
|
|
55
|
+
```
|
|
56
|
+
API: https://{fqdn} (configRefName = "api")
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
**`CREATE_ERROR`** — fetch logs (`SERVICE_DEPLOYMENTS_VIEW` permission required):
|
|
60
|
+
|
|
61
|
+
```graphql
|
|
62
|
+
# POST {HOSTING_SERVICE_BASE_URL}/graphql
|
|
63
|
+
query($c: ServiceDeploymentLogCondition) {
|
|
64
|
+
serviceDeploymentLogs(condition: $c, orderBy: TIMESTAMP_ASC) {
|
|
65
|
+
nodes { messageType message timestamp }
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
# variables: {"c": {"serviceDeploymentId": "{serviceDeploymentId}"}}
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
- **Config/manifest error** → fix the YAML, re-upload with an incremented
|
|
72
|
+
tag (e.g. `20260423.2`), re-deploy reusing the same `imageTag` and `piletRef`
|
|
73
|
+
- **Code/runtime error** → tell the user; do not retry until they push a fix,
|
|
74
|
+
then restart from the image build step
|
|
75
|
+
|
|
76
|
+
Always use a new deployment name — never modify an existing deployment.
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: manifest-review-and-upload
|
|
3
|
+
input:
|
|
4
|
+
- serviceId
|
|
5
|
+
- manifestPath (absolute path to mosaic-hosting-deployment-manifest.yaml)
|
|
6
|
+
- servicePath (for .env.template comparison)
|
|
7
|
+
- imageTag (used as uniqueTag for the manifest name)
|
|
8
|
+
output:
|
|
9
|
+
- manifestName (e.g. media-service-manifest-20260423.1 — passed as -m to
|
|
10
|
+
deploy)
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
# Manifest Review & Upload
|
|
14
|
+
|
|
15
|
+
## Existing Manifests
|
|
16
|
+
|
|
17
|
+
```graphql
|
|
18
|
+
# POST {HOSTING_SERVICE_BASE_URL}/graphql
|
|
19
|
+
query {
|
|
20
|
+
serviceDeploymentManifests(
|
|
21
|
+
filter: { serviceId: { equalTo: "{serviceId}" } }
|
|
22
|
+
orderBy: CREATED_DATE_DESC
|
|
23
|
+
first: 5
|
|
24
|
+
) {
|
|
25
|
+
nodes {
|
|
26
|
+
name
|
|
27
|
+
createdDate
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
Present as a numbered list (newest first) with `[0] Upload a new manifest` as the last option. Wait for the user to pick by number — never ask them to type a name manually. If the user picks an existing manifest, skip the upload step and use that name directly.
|
|
34
|
+
|
|
35
|
+
## Review
|
|
36
|
+
|
|
37
|
+
**Unresolved placeholders:** search for `REPLACE_WITH_VALID_` — stop and ask the
|
|
38
|
+
user to fill these in before uploading.
|
|
39
|
+
|
|
40
|
+
**Missing variables:** compare variable names in `{servicePath}/.env.template`
|
|
41
|
+
against `regularVariables` + `secureVariables` in the manifest. Surface any gaps
|
|
42
|
+
to the user (skip obviously dev-only vars like `GRAPHQL_GUI_ENABLED`).
|
|
43
|
+
|
|
44
|
+
**Secrets:** sensitive values can be injected at upload time without being
|
|
45
|
+
hardcoded in the YAML:
|
|
46
|
+
|
|
47
|
+
```yaml
|
|
48
|
+
secureVariables:
|
|
49
|
+
MY_SECRET: ${__ax_hosted__.dynamic.MY_SECRET}
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
`yarn util:load-vars` feeds root `.env` into the environment before the CLI
|
|
53
|
+
runs, making those values available for substitution. This is why manifest
|
|
54
|
+
upload must use the CLI and not the API directly.
|
|
55
|
+
|
|
56
|
+
## Upload
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
yarn util:load-vars mosaic hosting manifest upload \
|
|
60
|
+
-i {serviceId} \
|
|
61
|
+
-p {manifestPath} \
|
|
62
|
+
-n {serviceId}-manifest-{imageTag}
|
|
63
|
+
```
|