feat: make release chain traceable by sha
This commit is contained in:
parent
16a4d430a4
commit
7054ecae5e
21
.github/scripts/utils/preferred-image-ref.sh
vendored
Normal file
21
.github/scripts/utils/preferred-image-ref.sh
vendored
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
tags="$1"
|
||||||
|
preferred=""
|
||||||
|
|
||||||
|
while IFS= read -r line; do
|
||||||
|
if [[ "$line" == *":latest" ]]; then
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
if [[ -n "$line" ]]; then
|
||||||
|
preferred="$line"
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
done <<< "$tags"
|
||||||
|
|
||||||
|
if [[ -z "$preferred" ]]; then
|
||||||
|
preferred="$(echo "$tags" | head -n 1)"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "$preferred"
|
||||||
24
.github/workflows/pipeline.yml
vendored
24
.github/workflows/pipeline.yml
vendored
@ -46,7 +46,6 @@ jobs:
|
|||||||
outputs:
|
outputs:
|
||||||
target_host: ${{ steps.flags.outputs.target_host }}
|
target_host: ${{ steps.flags.outputs.target_host }}
|
||||||
run_apply: ${{ steps.flags.outputs.run_apply }}
|
run_apply: ${{ steps.flags.outputs.run_apply }}
|
||||||
image_tag: ${{ steps.flags.outputs.image_tag }}
|
|
||||||
push_image: ${{ steps.flags.outputs.push_image }}
|
push_image: ${{ steps.flags.outputs.push_image }}
|
||||||
push_latest: ${{ steps.flags.outputs.push_latest }}
|
push_latest: ${{ steps.flags.outputs.push_latest }}
|
||||||
steps:
|
steps:
|
||||||
@ -62,7 +61,6 @@ jobs:
|
|||||||
DEFAULT_TARGET_HOST: ${{ env.DEFAULT_TARGET_HOST }}
|
DEFAULT_TARGET_HOST: ${{ env.DEFAULT_TARGET_HOST }}
|
||||||
INPUT_TARGET_HOST: ${{ inputs.target_host }}
|
INPUT_TARGET_HOST: ${{ inputs.target_host }}
|
||||||
INPUT_RUN_APPLY: ${{ inputs.run_apply }}
|
INPUT_RUN_APPLY: ${{ inputs.run_apply }}
|
||||||
INPUT_IMAGE_TAG: ${{ inputs.image_tag }}
|
|
||||||
INPUT_PUSH_IMAGE: ${{ inputs.push_image }}
|
INPUT_PUSH_IMAGE: ${{ inputs.push_image }}
|
||||||
INPUT_PUSH_LATEST: ${{ inputs.push_latest }}
|
INPUT_PUSH_LATEST: ${{ inputs.push_latest }}
|
||||||
PR_BASE_SHA: ${{ github.event.pull_request.base.sha }}
|
PR_BASE_SHA: ${{ github.event.pull_request.base.sha }}
|
||||||
@ -81,7 +79,7 @@ jobs:
|
|||||||
SERVICE_IMAGE_NAME: accounts
|
SERVICE_IMAGE_NAME: accounts
|
||||||
outputs:
|
outputs:
|
||||||
service_image_repo: ${{ steps.service_image.outputs.repo }}
|
service_image_repo: ${{ steps.service_image.outputs.repo }}
|
||||||
service_preferred_tag: ${{ steps.service_preferred.outputs.tag }}
|
service_image_ref: ${{ steps.service_ref.outputs.image_ref }}
|
||||||
steps:
|
steps:
|
||||||
- name: Check Out Repository
|
- name: Check Out Repository
|
||||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||||
@ -110,16 +108,15 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
images: ${{ steps.service_image.outputs.repo }}
|
images: ${{ steps.service_image.outputs.repo }}
|
||||||
tags: |
|
tags: |
|
||||||
type=raw,value=${{ needs.prep.outputs.image_tag }},enable=${{ needs.prep.outputs.image_tag != '' }}
|
type=sha,format=long
|
||||||
type=sha,format=short,enable=${{ needs.prep.outputs.image_tag == '' }}
|
|
||||||
type=raw,value=latest,enable=${{ needs.prep.outputs.push_latest == 'true' || github.ref == 'refs/heads/main' }}
|
type=raw,value=latest,enable=${{ needs.prep.outputs.push_latest == 'true' || github.ref == 'refs/heads/main' }}
|
||||||
|
|
||||||
- name: Resolve Service Preferred Tag
|
- name: Resolve Service Image Ref
|
||||||
id: service_preferred
|
id: service_ref
|
||||||
run: |
|
run: |
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
tag="$(bash .github/scripts/utils/preferred-tag.sh "${{ steps.service_meta.outputs.tags }}")"
|
image_ref="$(bash .github/scripts/utils/preferred-image-ref.sh "${{ steps.service_meta.outputs.tags }}")"
|
||||||
echo "tag=${tag}" >> "$GITHUB_OUTPUT"
|
echo "image_ref=${image_ref}" >> "$GITHUB_OUTPUT"
|
||||||
|
|
||||||
- name: Build And Push Service Image
|
- name: Build And Push Service Image
|
||||||
uses: docker/build-push-action@471d1dc4e07e5cdedd4c2171150001c434f0b7a4 # v6.15.0
|
uses: docker/build-push-action@471d1dc4e07e5cdedd4c2171150001c434f0b7a4 # v6.15.0
|
||||||
@ -140,7 +137,7 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
outputs:
|
outputs:
|
||||||
image: ${{ needs.build.outputs.service_image_repo }}
|
image: ${{ needs.build.outputs.service_image_repo }}
|
||||||
preferred_tag: ${{ needs.build.outputs.service_preferred_tag }}
|
image_ref: ${{ needs.build.outputs.service_image_ref }}
|
||||||
run_apply: ${{ needs.prep.outputs.run_apply }}
|
run_apply: ${{ needs.prep.outputs.run_apply }}
|
||||||
pushed: "true"
|
pushed: "true"
|
||||||
steps:
|
steps:
|
||||||
@ -159,8 +156,8 @@ jobs:
|
|||||||
id: deploy_image_tag
|
id: deploy_image_tag
|
||||||
run: |
|
run: |
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
tag="${{ needs.build.outputs.service_preferred_tag }}"
|
image_ref="${{ needs.build.outputs.service_image_ref }}"
|
||||||
echo "value=${tag##*:}" >> "$GITHUB_OUTPUT"
|
echo "value=${image_ref##*:}" >> "$GITHUB_OUTPUT"
|
||||||
|
|
||||||
- name: Set Up Python
|
- name: Set Up Python
|
||||||
uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.0.0
|
uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.0.0
|
||||||
@ -209,6 +206,7 @@ jobs:
|
|||||||
validate:
|
validate:
|
||||||
name: Validate
|
name: Validate
|
||||||
needs:
|
needs:
|
||||||
|
- build
|
||||||
- deploy
|
- deploy
|
||||||
if: ${{ always() && needs.deploy.result == 'success' && needs.deploy.outputs.pushed == 'true' && needs.deploy.outputs.run_apply == 'true' }}
|
if: ${{ always() && needs.deploy.result == 'success' && needs.deploy.outputs.pushed == 'true' && needs.deploy.outputs.run_apply == 'true' }}
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
@ -217,4 +215,4 @@ jobs:
|
|||||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||||
|
|
||||||
- name: Validate Deployed Accounts Service
|
- name: Validate Deployed Accounts Service
|
||||||
run: bash ./scripts/github-actions/validate-deploy.sh https://accounts.svc.plus
|
run: bash ./scripts/github-actions/validate-deploy.sh "${{ needs.build.outputs.service_image_ref }}" https://accounts.svc.plus
|
||||||
|
|||||||
@ -5,6 +5,7 @@ service_compose_container_port: 8080
|
|||||||
service_compose_git_short_commit: "{{ lookup('ansible.builtin.env', 'GIT_SHORT_COMMIT') | default('manual', true) }}"
|
service_compose_git_short_commit: "{{ lookup('ansible.builtin.env', 'GIT_SHORT_COMMIT') | default('manual', true) }}"
|
||||||
service_compose_env_common:
|
service_compose_env_common:
|
||||||
CONFIG_TEMPLATE: /app/config/account.cloudrun.yaml
|
CONFIG_TEMPLATE: /app/config/account.cloudrun.yaml
|
||||||
|
IMAGE: "{{ service_compose_image }}"
|
||||||
service_compose_deploy_targets:
|
service_compose_deploy_targets:
|
||||||
- name: prod
|
- name: prod
|
||||||
deploy_subdomain_prefix: accounts
|
deploy_subdomain_prefix: accounts
|
||||||
@ -18,4 +19,3 @@ service_compose_deploy_targets:
|
|||||||
- accounts-preview.svc.plus
|
- accounts-preview.svc.plus
|
||||||
host_port: 18081
|
host_port: 18081
|
||||||
env: {}
|
env: {}
|
||||||
|
|
||||||
|
|||||||
@ -6,6 +6,7 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
"os"
|
"os"
|
||||||
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@ -15,7 +16,7 @@ import (
|
|||||||
"account/internal/store"
|
"account/internal/store"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestAgentUsersUseAccountUUIDAsStatsEmail(t *testing.T) {
|
func TestAgentUsersUseAccountEmailAsStatsEmail(t *testing.T) {
|
||||||
gin.SetMode(gin.TestMode)
|
gin.SetMode(gin.TestMode)
|
||||||
|
|
||||||
st := store.NewMemoryStore()
|
st := store.NewMemoryStore()
|
||||||
@ -74,12 +75,12 @@ func TestAgentUsersUseAccountUUIDAsStatsEmail(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, client := range payload.Clients {
|
for _, client := range payload.Clients {
|
||||||
if client.Email == user.ID {
|
if client.Email == strings.ToLower(strings.TrimSpace(user.Email)) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
t.Fatalf("expected stats email %q in payload, got %#v", user.ID, payload.Clients)
|
t.Fatalf("expected stats email %q in payload, got %#v", user.Email, payload.Clients)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestAccountUsageAndPolicyEndpoints(t *testing.T) {
|
func TestAccountUsageAndPolicyEndpoints(t *testing.T) {
|
||||||
|
|||||||
@ -76,7 +76,7 @@ func (h *handler) listAgentUsers(c *gin.Context) {
|
|||||||
if id != "" {
|
if id != "" {
|
||||||
clients = append(clients, xrayconfig.Client{
|
clients = append(clients, xrayconfig.Client{
|
||||||
ID: id,
|
ID: id,
|
||||||
Email: strings.TrimSpace(sandboxUser.ID),
|
Email: strings.ToLower(strings.TrimSpace(sandboxUser.Email)),
|
||||||
Flow: xrayconfig.DefaultFlow,
|
Flow: xrayconfig.DefaultFlow,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -92,7 +92,7 @@ func (h *handler) listAgentUsers(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
clients = append(clients, xrayconfig.Client{
|
clients = append(clients, xrayconfig.Client{
|
||||||
ID: id,
|
ID: id,
|
||||||
Email: strings.TrimSpace(u.ID),
|
Email: strings.ToLower(strings.TrimSpace(u.Email)),
|
||||||
Flow: xrayconfig.DefaultFlow,
|
Flow: xrayconfig.DefaultFlow,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
65
api/api.go
65
api/api.go
@ -13,6 +13,7 @@ import (
|
|||||||
"math/big"
|
"math/big"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
"os"
|
||||||
"reflect"
|
"reflect"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
@ -44,6 +45,13 @@ const defaultBridgeBootstrapTarget = "https://xworkmate-bridge.svc.plus"
|
|||||||
|
|
||||||
const sessionCookieName = "xc_session"
|
const sessionCookieName = "xc_session"
|
||||||
|
|
||||||
|
type imageVersionInfo struct {
|
||||||
|
ImageRef string `json:"image_ref"`
|
||||||
|
Tag string `json:"tag,omitempty"`
|
||||||
|
Commit string `json:"commit,omitempty"`
|
||||||
|
Version string `json:"version,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
type session struct {
|
type session struct {
|
||||||
userID string
|
userID string
|
||||||
expiresAt time.Time
|
expiresAt time.Time
|
||||||
@ -326,6 +334,17 @@ func RegisterRoutes(r *gin.Engine, opts ...Option) {
|
|||||||
c.JSON(http.StatusOK, gin.H{"status": "ok"})
|
c.JSON(http.StatusOK, gin.H{"status": "ok"})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
r.GET("/api/ping", func(c *gin.Context) {
|
||||||
|
info := parseImageVersionInfo(os.Getenv("IMAGE"))
|
||||||
|
c.JSON(http.StatusOK, gin.H{
|
||||||
|
"status": "ok",
|
||||||
|
"image": info.ImageRef,
|
||||||
|
"tag": info.Tag,
|
||||||
|
"commit": info.Commit,
|
||||||
|
"version": info.Version,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
authGroup := r.Group("/api/auth")
|
authGroup := r.Group("/api/auth")
|
||||||
|
|
||||||
authGroup.POST("/register", h.register)
|
authGroup.POST("/register", h.register)
|
||||||
@ -3039,6 +3058,52 @@ func (h *handler) isRootAccount(user *store.User) bool {
|
|||||||
return store.IsRootRole(user.Role) && strings.EqualFold(strings.TrimSpace(user.Email), store.RootAdminEmail)
|
return store.IsRootRole(user.Role) && strings.EqualFold(strings.TrimSpace(user.Email), store.RootAdminEmail)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func parseImageVersionInfo(imageRef string) imageVersionInfo {
|
||||||
|
ref := strings.TrimSpace(imageRef)
|
||||||
|
info := imageVersionInfo{ImageRef: ref}
|
||||||
|
if ref == "" {
|
||||||
|
return info
|
||||||
|
}
|
||||||
|
|
||||||
|
if idx := strings.LastIndex(ref, "@"); idx >= 0 {
|
||||||
|
ref = ref[:idx]
|
||||||
|
}
|
||||||
|
|
||||||
|
tag := ref
|
||||||
|
if idx := strings.LastIndex(tag, ":"); idx >= 0 && idx > strings.LastIndex(tag, "/") {
|
||||||
|
tag = tag[idx+1:]
|
||||||
|
}
|
||||||
|
tag = strings.TrimSpace(tag)
|
||||||
|
info.Tag = tag
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case isHexCommit(tag):
|
||||||
|
info.Commit = tag
|
||||||
|
info.Version = tag
|
||||||
|
case strings.HasPrefix(tag, "v") && len(tag) > 1:
|
||||||
|
info.Version = tag
|
||||||
|
default:
|
||||||
|
info.Version = tag
|
||||||
|
}
|
||||||
|
|
||||||
|
return info
|
||||||
|
}
|
||||||
|
|
||||||
|
func isHexCommit(value string) bool {
|
||||||
|
if len(value) < 7 || len(value) > 40 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
for _, r := range value {
|
||||||
|
switch {
|
||||||
|
case r >= '0' && r <= '9':
|
||||||
|
case r >= 'a' && r <= 'f':
|
||||||
|
default:
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
func respondError(c *gin.Context, status int, code, message string) {
|
func respondError(c *gin.Context, status int, code, message string) {
|
||||||
if status >= 500 {
|
if status >= 500 {
|
||||||
slog.Error("api_error", "status", status, "code", code, "message", message, "path", c.Request.URL.Path, "method", c.Request.Method)
|
slog.Error("api_error", "status", status, "code", code, "message", message, "path", c.Request.URL.Path, "method", c.Request.Method)
|
||||||
|
|||||||
@ -318,10 +318,10 @@ func TestAgentServerUsers_DefaultSyncIncludesSandboxAndRegularUsers(t *testing.T
|
|||||||
seenSandbox := false
|
seenSandbox := false
|
||||||
seenNormal := false
|
seenNormal := false
|
||||||
for _, c := range payload.Clients {
|
for _, c := range payload.Clients {
|
||||||
if c.Email == sandbox.ID && strings.TrimSpace(c.ID) != "" {
|
if c.Email == strings.ToLower(strings.TrimSpace(sandbox.Email)) && strings.TrimSpace(c.ID) != "" {
|
||||||
seenSandbox = true
|
seenSandbox = true
|
||||||
}
|
}
|
||||||
if c.Email == normal.ID && strings.TrimSpace(c.ID) != "" {
|
if c.Email == strings.ToLower(strings.TrimSpace(normal.Email)) && strings.TrimSpace(c.ID) != "" {
|
||||||
seenNormal = true
|
seenNormal = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1494,6 +1494,39 @@ func TestHealthzEndpoint(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestPingEndpointDerivesVersionFromImageEnv(t *testing.T) {
|
||||||
|
t.Setenv("IMAGE", "ghcr.io/example/accounts:abcdef1234567890abcdef1234567890abcdef12")
|
||||||
|
gin.SetMode(gin.TestMode)
|
||||||
|
|
||||||
|
router := gin.New()
|
||||||
|
RegisterRoutes(router)
|
||||||
|
|
||||||
|
req := httptest.NewRequest(http.MethodGet, "/api/ping", nil)
|
||||||
|
rr := httptest.NewRecorder()
|
||||||
|
router.ServeHTTP(rr, req)
|
||||||
|
|
||||||
|
if rr.Code != http.StatusOK {
|
||||||
|
t.Fatalf("expected ping endpoint to return 200, got %d", rr.Code)
|
||||||
|
}
|
||||||
|
|
||||||
|
var resp map[string]string
|
||||||
|
if err := json.Unmarshal(rr.Body.Bytes(), &resp); err != nil {
|
||||||
|
t.Fatalf("failed to decode ping response: %v", err)
|
||||||
|
}
|
||||||
|
if got := resp["image"]; got != "ghcr.io/example/accounts:abcdef1234567890abcdef1234567890abcdef12" {
|
||||||
|
t.Fatalf("expected image ref from env, got %q", got)
|
||||||
|
}
|
||||||
|
if got := resp["tag"]; got != "abcdef1234567890abcdef1234567890abcdef12" {
|
||||||
|
t.Fatalf("expected tag derived from image ref, got %q", got)
|
||||||
|
}
|
||||||
|
if got := resp["commit"]; got != "abcdef1234567890abcdef1234567890abcdef12" {
|
||||||
|
t.Fatalf("expected commit derived from image ref, got %q", got)
|
||||||
|
}
|
||||||
|
if got := resp["version"]; got != "abcdef1234567890abcdef1234567890abcdef12" {
|
||||||
|
t.Fatalf("expected version derived from image ref, got %q", got)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestPasswordResetFlow(t *testing.T) {
|
func TestPasswordResetFlow(t *testing.T) {
|
||||||
gin.SetMode(gin.TestMode)
|
gin.SetMode(gin.TestMode)
|
||||||
|
|
||||||
|
|||||||
@ -20,7 +20,6 @@ fi
|
|||||||
if [[ "${GITHUB_EVENT_NAME}" == "workflow_dispatch" ]]; then
|
if [[ "${GITHUB_EVENT_NAME}" == "workflow_dispatch" ]]; then
|
||||||
TARGET_HOST="${INPUT_TARGET_HOST:-${TARGET_HOST}}"
|
TARGET_HOST="${INPUT_TARGET_HOST:-${TARGET_HOST}}"
|
||||||
[[ "${INPUT_RUN_APPLY:-true}" == "true" ]] && RUN_APPLY=true || RUN_APPLY=false
|
[[ "${INPUT_RUN_APPLY:-true}" == "true" ]] && RUN_APPLY=true || RUN_APPLY=false
|
||||||
IMAGE_TAG="${INPUT_IMAGE_TAG:-}"
|
|
||||||
[[ "${INPUT_PUSH_IMAGE:-true}" == "true" ]] && PUSH_IMAGE=true || PUSH_IMAGE=false
|
[[ "${INPUT_PUSH_IMAGE:-true}" == "true" ]] && PUSH_IMAGE=true || PUSH_IMAGE=false
|
||||||
[[ "${INPUT_PUSH_LATEST:-false}" == "true" ]] && PUSH_LATEST=true || PUSH_LATEST=false
|
[[ "${INPUT_PUSH_LATEST:-false}" == "true" ]] && PUSH_LATEST=true || PUSH_LATEST=false
|
||||||
[[ "${INPUT_RUN_BASE_IMAGES:-false}" == "true" ]] && RUN_BASE_IMAGES=true || RUN_BASE_IMAGES=false
|
[[ "${INPUT_RUN_BASE_IMAGES:-false}" == "true" ]] && RUN_BASE_IMAGES=true || RUN_BASE_IMAGES=false
|
||||||
|
|||||||
@ -1,12 +1,58 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
BASE_URL="${1:-https://accounts.svc.plus}"
|
IMAGE_REF="${1:?image_ref is required}"
|
||||||
|
BASE_URL="${2:-https://accounts.svc.plus}"
|
||||||
|
|
||||||
curl \
|
image_ref="$(printf '%s' "${IMAGE_REF}" | tr -d '\n' | xargs)"
|
||||||
--silent \
|
if [[ -z "${image_ref}" ]]; then
|
||||||
--show-error \
|
echo "image_ref is required" >&2
|
||||||
--fail \
|
exit 1
|
||||||
--location \
|
fi
|
||||||
--max-time 20 \
|
|
||||||
"${BASE_URL}/healthz" | grep -q '"status":"ok"'
|
image_no_digest="${image_ref%@*}"
|
||||||
|
tag="${image_no_digest##*:}"
|
||||||
|
if [[ "${image_no_digest}" == "${tag}" ]]; then
|
||||||
|
tag=""
|
||||||
|
fi
|
||||||
|
|
||||||
|
commit=""
|
||||||
|
version="${tag}"
|
||||||
|
|
||||||
|
if [[ "${tag}" =~ ^[0-9a-f]{7,40}$ ]]; then
|
||||||
|
commit="${tag}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
ping_json="$(
|
||||||
|
curl \
|
||||||
|
--silent \
|
||||||
|
--show-error \
|
||||||
|
--fail \
|
||||||
|
--location \
|
||||||
|
--max-time 20 \
|
||||||
|
"${BASE_URL}/api/ping"
|
||||||
|
)"
|
||||||
|
|
||||||
|
PING_JSON="${ping_json}" python3 - "${image_ref}" "${tag}" "${commit}" "${version}" <<'PY'
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
|
||||||
|
image_ref, tag, commit, version = sys.argv[1:5]
|
||||||
|
payload = json.loads(os.environ["PING_JSON"])
|
||||||
|
|
||||||
|
if payload.get("status") != "ok":
|
||||||
|
raise SystemExit("ping status not ok")
|
||||||
|
|
||||||
|
if payload.get("image") != image_ref:
|
||||||
|
raise SystemExit(f"expected image {image_ref!r}, got {payload.get('image')!r}")
|
||||||
|
|
||||||
|
if tag and payload.get("tag") != tag:
|
||||||
|
raise SystemExit(f"expected tag {tag!r}, got {payload.get('tag')!r}")
|
||||||
|
|
||||||
|
if commit and payload.get("commit") != commit:
|
||||||
|
raise SystemExit(f"expected commit {commit!r}, got {payload.get('commit')!r}")
|
||||||
|
|
||||||
|
if version and payload.get("version") != version:
|
||||||
|
raise SystemExit(f"expected version {version!r}, got {payload.get('version')!r}")
|
||||||
|
PY
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user