Files
CASAN/scripts/smoke-release-artifact.sh
thanhnv 06c404084d
CASAN Supply Chain and Provenance / verify-scan-attest (push) Canceled after 0s
CASAN CI Gate / Frontend Tests (H3 gate) (push) Canceled after 0s
CASAN CI Gate / CASAN Security Gate + Vault KMS (H4/H5) (push) Canceled after 0s
CASAN CI Gate / Build & Deploy OKR → /opt/webapps/okr (push) Canceled after 0s
CASAN Harness CI / harness (push) Canceled after 0s
feat(casan): add native plugin facade
2026-08-18 16:26:27 +07:00

108 lines
3.3 KiB
Bash
Executable File

#!/usr/bin/env bash
set -euo pipefail
# Smoke the release exactly as a customer receives it. This intentionally
# extracts into a fresh directory and never resolves files from the source tree.
#
# Usage: scripts/smoke-release-artifact.sh dist/casan-<bundle>-vX.Y.Z.tar.gz
# Env: CASAN_ARTIFACT_SMOKE_RUN_TESTS=1 # platform: npm ci + tests + build
ARCHIVE="${1:-}"
[[ -n "$ARCHIVE" && -f "$ARCHIVE" ]] || {
echo "ARTIFACT_SMOKE_FAIL reason=archive_missing path=${ARCHIVE:-unset}" >&2
exit 64
}
ARCHIVE="$(cd "$(dirname "$ARCHIVE")" && pwd)/$(basename "$ARCHIVE")"
WORK="$(mktemp -d)"
cleanup() { rm -rf "$WORK"; }
trap cleanup EXIT
tar -xzf "$ARCHIVE" -C "$WORK"
roots=()
while IFS= read -r directory; do
roots+=("$directory")
done < <(find "$WORK" -mindepth 1 -maxdepth 1 -type d -print)
[[ "${#roots[@]}" -eq 1 ]] || {
echo "ARTIFACT_SMOKE_FAIL reason=unexpected_root_count count=${#roots[@]}" >&2
exit 1
}
ROOT="${roots[0]}"
required=(
BUNDLE-MANIFEST.txt
SHA256SUMS
VERSION
bin/casan
packages/casan-harness
.codex-plugin/plugin.json
.claude-plugin/plugin.json
.claude-plugin/marketplace.json
skills/casan/SKILL.md
)
for path in "${required[@]}"; do
[[ -e "$ROOT/$path" ]] || {
echo "ARTIFACT_SMOKE_FAIL reason=required_path_missing path=$path" >&2
exit 1
}
done
for path in \
packages/casan-harness/tests \
packages/casan-harness/level5 \
packages/casan-harness/scripts/bash/ci-harness-gate.sh \
packages/casan-harness/scripts/bash/security-gate.sh \
packages/casan-harness/scripts/bash/test-integrity.py \
packages/casan-devkit/tests; do
[[ ! -e "$ROOT/$path" ]] || {
echo "ARTIFACT_SMOKE_FAIL reason=source_only_path_present path=$path" >&2
exit 1
}
done
(cd "$ROOT" && shasum -a 256 -c SHA256SUMS >/dev/null)
VERSION="$(tr -d '[:space:]' < "$ROOT/VERSION")"
CLI_VERSION="$(cd "$ROOT" && ./bin/casan version)"
[[ "$CLI_VERSION" == "casan $VERSION" ]] || {
echo "ARTIFACT_SMOKE_FAIL reason=cli_version_mismatch expected=$VERSION actual=$CLI_VERSION" >&2
exit 1
}
(cd "$ROOT" && ./bin/casan help >/dev/null)
STATUS="$(awk '/^status:/ {print $2}' "$ROOT/BUNDLE-MANIFEST.txt")"
BUNDLE="$(awk '/^bundle:/ {print $2}' "$ROOT/BUNDLE-MANIFEST.txt")"
if [[ "$BUNDLE" == "platform" ]]; then
platform_required=(
packages/casan-control-panel/backend/package.json
packages/casan-control-panel/frontend/package.json
Dockerfile.control-panel-api
Dockerfile.control-panel-ui
docker-compose.control-panel.yml
docker-compose.control-panel.local.yml
nginx/control-panel.conf
infra/production/README.md
docs/security/CONTROL_PANEL_AUTH_HARDENING.md
)
for path in "${platform_required[@]}"; do
[[ -e "$ROOT/$path" ]] || {
echo "ARTIFACT_SMOKE_FAIL reason=platform_path_missing path=$path" >&2
exit 1
}
done
[[ -f "$ROOT/PREVIEW-INCOMPLETE.txt" ]] || {
echo "ARTIFACT_SMOKE_FAIL reason=preview_marker_missing" >&2
exit 1
}
if [[ "${CASAN_ARTIFACT_SMOKE_RUN_TESTS:-0}" == "1" ]]; then
command -v npm >/dev/null 2>&1 || {
echo "ARTIFACT_SMOKE_FAIL reason=npm_missing" >&2
exit 1
}
(cd "$ROOT" && npm ci && npm run console:test && npm run console:build)
fi
fi
echo "ARTIFACT_SMOKE_PASS bundle=$BUNDLE status=$STATUS version=$VERSION extracted=true checksums=true"