Fix deployment verification and clean submission

هذا الالتزام موجود في:
yassinelagamy
2026-07-26 21:40:12 +03:00
الأصل 17d02735a1
التزام 60b9e2c38e
23 ملفات معدلة مع 799 إضافات و952 حذوفات

عرض الملف

@@ -2,137 +2,147 @@
## Pipeline overview
The workflow builds the API from `q1-deploy-monitor/app`, publishes two Docker Hub tags, deploys the immutable commit tag to a separate staging application, pauses for manual approval, and then deploys the exact same image to production. Promoting the same immutable `${{ github.sha }}` tag prevents staging and production from running artifacts built from different source.
The workflow builds the API from `q1-deploy-monitor/app`, embeds the Git commit
SHA in the image, and publishes immutable SHA and `latest` tags to Docker Hub.
It then starts that immutable image in an isolated GitHub Actions runner,
validates `/health`, pauses at the protected `production` Environment, and
verifies that the approved Ghaymah application is serving the same SHA.
```mermaid
flowchart LR
A["Commit to main"] --> B["Build image"]
B --> C["Push SHA and latest tags<br/>to Docker Hub"]
C --> D["Deploy staging<br/>(automatic)"]
D --> E{"Manual approval<br/>GitHub Environment"}
E -->|Approved| F["Deploy production"]
E -->|Rejected| G["Stop deployment"]
C --> D["Ephemeral staging container<br/>automatic"]
D --> E["Health and release check"]
E --> F{"Production Environment<br/>required reviewer"}
F -->|Approved| G["Ghaymah production"]
G --> H["Verify /health<br/>and exact release SHA"]
F -->|Rejected| I["Stop promotion"]
```
The workflow runs on:
The free Ghaymah account used for this assessment permits five total resources.
The two required live applications (`ghaymah-api` and `mithal-monitor`) already
consume the available allocation together with their supporting resources. A
third Ghaymah application was tested and rejected by the platform with the
documented account message `Resource limit exceeded ... maximum 5 resources`.
Staging is therefore an ephemeral container on the GitHub-hosted runner. It runs
the exact image that will be promoted, while production remains the real
Ghaymah service.
- A push to `main`.
- A manual `workflow_dispatch` run.
The workflow runs on a push to `main` and through `workflow_dispatch`. It uses:
It uses these GitHub Actions secrets:
| Secret | Purpose |
| Setting | Purpose |
|---|---|
| `DOCKERHUB_USERNAME` | Docker Hub account/namespace used to authenticate and construct the image name. |
| `DOCKERHUB_TOKEN` | Docker Hub access token used to push images. |
| `GHAYMAH_API_TOKEN` | Reserved for the deployment adapter if a supported API or CLI authentication flow is confirmed. |
Optional repository or environment variables `GHAYMAH_STAGING_APP` and `GHAYMAH_PRODUCTION_APP` select the target applications. The workflow defaults conceptually to `myapp-staging` and `myapp-production`.
| Secret `DOCKERHUB_USERNAME` | Docker Hub account and image namespace. |
| Secret `DOCKERHUB_TOKEN` | Read/write Docker Hub access token. |
| Variable `GHAYMAH_STAGING_APP` | Display name for the ephemeral staging service. |
| Variable `GHAYMAH_PRODUCTION_APP` | Name of the live Ghaymah application. |
| Variable `GHAYMAH_PRODUCTION_URL` | Public base URL used for the production verification. |
Images are published as:
```text
docker.io/<user>/ghaymah-api:<git-commit-sha>
docker.io/<user>/ghaymah-api:latest
docker.io/agamy74/ghaymah-api:<git-commit-sha>
docker.io/agamy74/ghaymah-api:latest
```
The SHA tag is used for deployment because it is immutable and auditable. `latest` is a convenience tag and should not be the production source of truth.
Ghaymah's public documentation describes deployment from a container image URL entered in its dashboard: image URL, application name, port, public-access setting, and environment variables are supplied before selecting **Deploy**. A Ghaymah-hosted registry is not assumed. If one becomes available, only the registry login server and image prefix need to change; the build and promotion design remains the same.
The authenticated dashboard confirms that manual deployment supports a container image URL and an optional **Registry Pull Secret**, and that **External Integrations** currently offers a Docker Hub connection. This validates Docker Hub as the registry used by this workflow; no Ghaymah-hosted registry endpoint or push syntax was exposed in the dashboard reviewed on 2026-07-26.
Only the SHA tag is promoted. The Dockerfile receives `RELEASE_SHA` as a build
argument and `/health` returns it as `release`. The verification script fails if
production is healthy but still serves an older image.
## Manual approval
Manual approval is implemented with a GitHub Environment named `production`. The workflow declares:
The production gate is implemented through a GitHub Environment named
`production`:
```yaml
environment: production
```
Required reviewers are configured in the GitHub repository UI, not in workflow YAML:
Required reviewers are configured in **Settings → Environments → production**,
not in YAML. This repository has `yassinelagamy` configured as the required
reviewer. The workflow pauses after staging and cannot start the production job
until that reviewer approves it.
1. Open **Settings → Environments**.
2. Create or select the `production` environment.
3. Enable the deployment protection rule for required reviewers.
4. Add the people or teams authorized to approve production deployments.
5. Store production-scoped secrets or variables in this environment where appropriate.
Because Ghaymah CLI `0.0.24` does not document non-interactive token
authentication or the external-image update field, promotion currently uses
this controlled procedure:
After staging succeeds, the `deploy-production` job enters a waiting state. The run pauses until an authorized reviewer approves it; rejection prevents the production deployment. The approval protects only production—staging continues to deploy automatically.
1. The workflow builds and verifies the immutable image in staging.
2. An operator updates the `ghaymah-api` image URL in the authenticated Ghaymah
dashboard to the printed SHA tag.
3. The required reviewer approves the GitHub `production` Environment.
4. The production job calls `/health` and succeeds only when `release` equals
the workflow commit SHA.
This is intentionally a manual promotion with automated verification. It does
not claim that an undocumented command deployed the application.
## Staging vs Production
Staging and production should be two separate Ghaymah applications, such as `myapp-staging` and `myapp-production`, with independent configuration and environment variables.
| Area | Staging | Production |
|---|---|---|
| Purpose | Validate the release in a production-like environment before promotion. | Serve the live customer workload. |
| Data | Synthetic, anonymized, or disposable test data. | Real customer/business data governed by retention and privacy controls. |
| Scale/replicas | Smaller footprint; enough replicas for functional and targeted load tests. | Sized for peak traffic, resilience, and operational headroom. |
| Secrets | Staging-only credentials with limited permissions. | Production-only credentials, tightly scoped and independently rotated. |
| Access control | Engineering and QA access; may be restricted from the public internet. | Least-privilege operational access; public access only where the service requires it. |
| Alerting thresholds | Useful for validation but may be less sensitive or routed to non-paging channels. | SLO-based thresholds with paging for user-impacting failures. |
| Deploy cadence | Automatic after each successful build from `main`. | Only after staging succeeds and a reviewer approves the deployment. |
| Who can approve | No approval required for this pipeline. | Reviewers assigned to the GitHub `production` Environment. |
| Purpose | Validate the exact candidate image before promotion. | Serve the public workload on Ghaymah. |
| Data | Synthetic or disposable test data. | Real application data and traffic. |
| Scale/replicas | One short-lived CI container for this free-tier assessment. | Ghaymah instance sized for availability and measured demand. |
| Secrets | Only build/test credentials; no production secrets. | Production-only values stored in protected platform or environment settings. |
| Access control | Reachable only inside the GitHub Actions runner. | Public endpoint; administrative access restricted to the Ghaymah account. |
| Alerting thresholds | Fast feedback on startup, health, and release identity. | SLO-based uptime, latency, memory, restart, and OOM alerts. |
| Deploy cadence | Automatic on each push to `main`. | Manual promotion after successful staging. |
| Who can approve | No reviewer required. | Required reviewer on the GitHub `production` Environment. |
Both applications receive the same immutable image tag, while their data, secrets, scale, access rules, and environment variables remain isolated.
On a paid allocation, staging should be a second Ghaymah application with its
own variables, secrets, capacity, and URL. The image and release verification
steps remain unchanged.
## Ghaymah CLI integration
### Verified public CLI commands
Ghaymah now publicly documents the `gy` CLI, including installation, interactive login, project management, Dockerfile-based application initialization and launch, and log retrieval. The currently documented flow is:
The verified public CLI installation and inspection commands are:
```bash
# Ghaymah-specific installation command confirmed from the official documentation.
curl -sSL https://cli.ghaymah.systems/install.sh | bash
source ~/.bashrc
# Ghaymah-specific commands confirmed with CLI 0.0.24.
gy version
gy auth login
gy auth login --email '<email>' --password '<password>'
gy auth status
gy resource project get
gy resource app init --project-id <PROJECT_ID> --name <APP_NAME>
gy resource app launch [PATH]
gy resource app init --project-id '<project-id>' --name '<app-name>'
gy resource app launch .
gy resource app logs
gy resource app update <APP_ID> --set '<CONFIRMED_UPDATE_FIELDS>'
gy resource app update '<app-id>' --set '<documented-fields>'
```
`app init` creates `.ghaymah.json`; the documented example includes the application ID/name, project ID, exposed port, public-access configuration, resource tier, and Dockerfile name. `app launch` builds the local Dockerfile and deploys that application.
The workflow installs the CLI and runs `gy version` in both deployment jobs so
the integration dependency is continuously checked. It does not place a user
password in CI. Public CLI help for version `0.0.24` exposes email/password
login, but no API-token flag, and its generic `app update --set` help does not
identify the field for an externally built container image.
Official sources:
The authenticated dashboard does provide a verified deployment route: enter a
container image URL, application name, port, public-access choice, environment
variables, and an optional registry pull secret, then deploy or update the
application. That dashboard route is used for production promotion until
Ghaymah publishes a service-account/token flow and an external-image update
schema.
`scripts/verify_deployment.sh` is the CI boundary after promotion:
```bash
bash scripts/verify_deployment.sh \
--app "$GHAYMAH_APP_NAME" \
--url "$GHAYMAH_PRODUCTION_URL" \
--expected-release "$GITHUB_SHA"
```
It retries `/health`, requires `status=ok`, compares the live `release` to the
approved SHA, writes evidence to the GitHub job summary, and exits nonzero for
an unavailable or stale deployment.
Official references:
- [Ghaymah CLI documentation](https://ghaymah.systems/docs)
- [Ghaymah CLI overview](https://ghaymah.systems/cli)
### CI integration gap
Direct inspection of CLI version `0.0.24` on 2026-07-26 established that `gy auth login` accepts `--email` and `--password`; it does not expose an API-token flag. It also established that `gy resource app update <APP_ID>` accepts JSON input or dot notation through `--set`.
The public documentation and CLI help still do **not** specify:
- A `GHAYMAH_API_TOKEN` login flow suitable for an ephemeral GitHub Actions runner.
- The JSON field used to update an existing application to a specific externally built image URL/tag.
- A login server and push commands for a Ghaymah-hosted registry; the authenticated dashboard instead exposes Docker Hub integration.
<!-- VERIFY: Confirm whether Ghaymah supports API-token authentication and identify the external-image field accepted by `gy resource app update`. -->
Consequently, the workflow safely builds and pushes the immutable Docker Hub image, installs the documented CLI, prints the exact deployment target, and calls `scripts/ghaymah_deploy.sh`. The adapter deliberately exits unsuccessfully after producing a clear deployment handoff; it never reports success for a deployment that did not occur.
Until the missing CI syntax is confirmed, the image deployment procedure is:
1. Open the target Ghaymah application in the dashboard.
2. Update its container image URL to `docker.io/<user>/ghaymah-api:<git-commit-sha>`.
3. Confirm the application name, exposed port, public-access setting, and environment variables.
4. Select **Deploy** and validate application health.
5. Repeat for production only after the GitHub Environment approval.
The staging and production workflow steps print the exact SHA-tagged image and target application, then call:
<!-- VERIFY: Replace this fail-safe adapter with confirmed non-interactive authentication and external-image update syntax. -->
```bash
bash scripts/ghaymah_deploy.sh \
--app "$GHAYMAH_APP_NAME" \
--image "$DEPLOY_IMAGE"
```
The workflow supplies `GHAYMAH_API_TOKEN` through the environment and never places it in a command-line argument. Once Ghaymah confirms the required syntax, the adapter should authenticate without logging the token, update the application's image URL, wait for rollout completion, validate `/health`, and return a nonzero exit status if deployment or health validation fails.
- [Docker login action](https://github.com/docker/login-action)
- [Docker build and push action](https://github.com/docker/build-push-action)