169 lines
5.4 KiB
Bash
169 lines
5.4 KiB
Bash
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
|
|
repo_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
|
strict_auth_server_audit=0
|
|
skip_audits=0
|
|
|
|
usage() {
|
|
cat <<'EOF'
|
|
Usage:
|
|
scripts/run-hypertwist-web-surface-validation.sh [--strict-auth-server-audit] [--skip-audits]
|
|
|
|
Runs the current first-party HyperTwist web-surface validation packet:
|
|
- website type-check, focused tests, and production build
|
|
- website/server type-check and full test suite
|
|
- Content/Browser shell verification and production build
|
|
- production dependency audits for website, website/server, and Content/Browser
|
|
|
|
Current auth-server nuance:
|
|
the default mode accepts the known upstream `supertokens-node -> nodemailer`
|
|
production advisory as a documented residual warning. Pass
|
|
`--strict-auth-server-audit` to fail on that residual too.
|
|
EOF
|
|
}
|
|
|
|
while [[ $# -gt 0 ]]; do
|
|
case "$1" in
|
|
--strict-auth-server-audit)
|
|
strict_auth_server_audit=1
|
|
;;
|
|
--skip-audits)
|
|
skip_audits=1
|
|
;;
|
|
-h|--help)
|
|
usage
|
|
exit 0
|
|
;;
|
|
*)
|
|
echo "Unknown argument: $1" >&2
|
|
usage >&2
|
|
exit 1
|
|
;;
|
|
esac
|
|
shift
|
|
done
|
|
|
|
run_step() {
|
|
local description="$1"
|
|
shift
|
|
printf '\n[%s] %s\n' "$(date -u '+%H:%M:%S')" "$description"
|
|
(
|
|
cd "$repo_root"
|
|
"$@"
|
|
)
|
|
}
|
|
|
|
run_clean_prod_audit() {
|
|
local workdir="$1"
|
|
local label="$2"
|
|
|
|
printf '\n[%s] %s production audit\n' "$(date -u '+%H:%M:%S')" "$label"
|
|
(
|
|
cd "$workdir"
|
|
npm audit --omit=dev --audit-level=high
|
|
)
|
|
}
|
|
|
|
run_auth_server_audit() {
|
|
local workdir="$repo_root/website/server"
|
|
local audit_json
|
|
|
|
printf '\n[%s] website/server production audit\n' "$(date -u '+%H:%M:%S')"
|
|
audit_json="$(
|
|
cd "$workdir"
|
|
npm audit --omit=dev --json || true
|
|
)"
|
|
|
|
if [[ -z "$audit_json" ]]; then
|
|
echo "website/server audit returned no output." >&2
|
|
return 1
|
|
fi
|
|
|
|
AUDIT_JSON="$audit_json" STRICT_AUTH_SERVER_AUDIT="$strict_auth_server_audit" node <<'EOF'
|
|
const report = JSON.parse(process.env.AUDIT_JSON || '{}')
|
|
const strict = process.env.STRICT_AUTH_SERVER_AUDIT === '1'
|
|
const vulnerabilities = report.vulnerabilities || {}
|
|
const metadata = report.metadata?.vulnerabilities || {}
|
|
const total = Number(metadata.total || 0)
|
|
|
|
if (total === 0) {
|
|
console.log('website/server production audit is clean.')
|
|
process.exit(0)
|
|
}
|
|
|
|
const keys = Object.keys(vulnerabilities).sort()
|
|
const expectedKeys = ['nodemailer', 'supertokens-node']
|
|
const nodemailer = vulnerabilities.nodemailer
|
|
const supertokens = vulnerabilities['supertokens-node']
|
|
const matchesKnownResidual =
|
|
metadata.info === 0 &&
|
|
metadata.low === 0 &&
|
|
metadata.moderate === 0 &&
|
|
metadata.high === 2 &&
|
|
metadata.critical === 0 &&
|
|
keys.length === expectedKeys.length &&
|
|
expectedKeys.every((key, index) => keys[index] === key) &&
|
|
nodemailer?.name === 'nodemailer' &&
|
|
nodemailer?.severity === 'high' &&
|
|
Array.isArray(nodemailer?.effects) &&
|
|
nodemailer.effects.length === 1 &&
|
|
nodemailer.effects[0] === 'supertokens-node' &&
|
|
Array.isArray(nodemailer?.nodes) &&
|
|
nodemailer.nodes.length === 1 &&
|
|
nodemailer.nodes[0] === 'node_modules/nodemailer' &&
|
|
supertokens?.name === 'supertokens-node' &&
|
|
supertokens?.severity === 'high' &&
|
|
Array.isArray(supertokens?.via) &&
|
|
supertokens.via.length === 1 &&
|
|
supertokens.via[0] === 'nodemailer'
|
|
|
|
if (matchesKnownResidual && !strict) {
|
|
console.log(
|
|
'website/server production audit retains the documented upstream residual advisory: supertokens-node -> nodemailer.',
|
|
)
|
|
process.exit(0)
|
|
}
|
|
|
|
console.error('website/server production audit found unexpected or strict-mode-blocking vulnerabilities.')
|
|
console.error(JSON.stringify(report, null, 2))
|
|
process.exit(1)
|
|
EOF
|
|
}
|
|
|
|
run_step "website type-check" npm --prefix website run type-check
|
|
run_step \
|
|
"higher-dimensional packaged-validation summary freshness" \
|
|
node scripts/render-hypertwist-web-package-validation-summary.mjs --check
|
|
run_step \
|
|
"website focused route/auth/release validation" \
|
|
npm --prefix website test -- --run \
|
|
src/__tests__/package-validation.test.ts \
|
|
src/__tests__/platform-auth.bootstrap.test.tsx \
|
|
src/__tests__/download-center-page.test.tsx \
|
|
src/__tests__/protected-app-pages.test.tsx \
|
|
src/__tests__/DashboardOverviewPage.test.tsx \
|
|
src/__tests__/app-route-tree.test.tsx \
|
|
src/__tests__/public-route-registry.test.ts \
|
|
src/__tests__/route-shells.test.tsx \
|
|
src/__tests__/release-manifest.test.ts \
|
|
src/__tests__/public-marketing-pages.test.tsx \
|
|
src/__tests__/public-auth-pages.test.tsx
|
|
run_step "website production build" npm --prefix website run build
|
|
run_step "website/server type-check" npm --prefix website/server run type-check
|
|
run_step "website/server test suite" npm --prefix website/server test -- --run
|
|
run_step "Content/Browser shell verification" npm --prefix Content/Browser run verify:shell
|
|
run_step "Content/Browser production build" npm --prefix Content/Browser run build
|
|
|
|
if [[ "$skip_audits" -eq 0 ]]; then
|
|
run_clean_prod_audit "$repo_root/website" "website"
|
|
run_auth_server_audit
|
|
run_clean_prod_audit "$repo_root/Content/Browser" "Content/Browser"
|
|
else
|
|
printf '\n[%s] Skipping production audits by request.\n' "$(date -u '+%H:%M:%S')"
|
|
fi
|
|
|
|
printf '\n[%s] HyperTwist web-surface validation completed successfully.\n' "$(date -u '+%H:%M:%S')"
|
|
if [[ "$skip_audits" -eq 0 && "$strict_auth_server_audit" -eq 0 ]]; then
|
|
echo "Auth-server note: known upstream supertokens-node -> nodemailer residual is accepted in default mode until upstream-compatible remediation exists."
|
|
fi
|