fix(m4): 对齐用量价格与发布契约

This commit is contained in:
tbphp committed 2026-07-27 08:09:56 +08:00
1 parent 4ab71ce123
commit c6b5525cf7
43 files changed
+2359 -824

No files matched your search

+14 -5
View File
@@ -4,6 +4,7 @@ umask 077
release_version="${RELEASE_VERSION:-v2.0.0-local}"
suffix="${RELEASE_SMOKE_SUFFIX:-local-$$}"
source_image="${RELEASE_SMOKE_SOURCE_IMAGE:-}"
case "${suffix}" in
*[!A-Za-z0-9_-]*)
printf 'RELEASE_SMOKE_SUFFIX contains unsupported characters\n' >&2
@@ -117,10 +118,16 @@ case "${docker_arch}" in
;;
esac
docker build \
--platform "${platform}" \
--build-arg "VERSION=${release_version}" \
-t "${image}" .
if [[ -n "${source_image}" ]]; then
test "${source_image}" != "${image}"
docker pull --platform "${platform}" "${source_image}"
docker image tag "${source_image}" "${image}"
else
docker build \
--platform "${platform}" \
--build-arg "VERSION=${release_version}" \
-t "${image}" .
fi
test "$(docker image inspect -f '{{.Config.User}}' "${image}")" = "10001:10001"
docker volume create "${volume}" >/dev/null
@@ -326,7 +333,9 @@ node -e '
const prices=JSON.parse(fs.readFileSync(process.argv[2],"utf8"));
const usage=JSON.parse(fs.readFileSync(process.argv[3],"utf8"));
if(!groups.data.some(item=>item.name==="Task13 Release Smoke Group")) process.exit(1);
if(!prices.data.some(item=>item.pattern==="task13-release-model"&&item.source==="user")) process.exit(1);
if(!prices.data.overrides.some(
item=>item.pattern==="task13-release-model"&&item.source==="user"
)) process.exit(1);
if(usage.data.summary.request_count<1||usage.data.summary.total_tokens!==12) process.exit(1);
' \
"${task_tmp}/groups-second.json" \
+26
View File
@@ -0,0 +1,26 @@
#!/usr/bin/env bash
set -euo pipefail
image="${1:?image is required}"
output=
if output="$(
docker buildx imagetools inspect \
"${image}" \
--format '{{.Manifest.Digest}}' 2>&1
)"; then
test -n "${output}"
printf '%s' "${output}"
exit 0
fi
if grep -Eqi 'manifest unknown|manifest_unknown' <<<"${output}" ||
{
grep -Fqi -- "${image}" <<<"${output}" &&
grep -Eqi 'not found|(^|[^0-9])404([^0-9]|$)' <<<"${output}"
}; then
printf 'absent'
exit 0
fi
printf '%s\n' "${output}" >&2
exit 1
+226
View File
@@ -0,0 +1,226 @@
$ErrorActionPreference = "Stop"
$binary = $env:RELEASE_SMOKE_BINARY
$checksumFile = $env:RELEASE_SMOKE_CHECKSUM_FILE
$releaseVersion = $env:RELEASE_VERSION
$port = if ($env:RELEASE_SMOKE_PORT) { $env:RELEASE_SMOKE_PORT } else { "39113" }
foreach ($required in @($binary, $checksumFile, $releaseVersion)) {
if ([string]::IsNullOrWhiteSpace($required)) {
throw "RELEASE_SMOKE_BINARY, RELEASE_SMOKE_CHECKSUM_FILE, and RELEASE_VERSION are required"
}
}
Add-Type -TypeDefinition @'
using System;
using System.ComponentModel;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Text;
public static class ReleaseNativeProcess
{
private const uint CREATE_NEW_PROCESS_GROUP = 0x00000200;
private const uint CTRL_BREAK_EVENT = 1;
private const int ERROR_ACCESS_DENIED = 5;
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
private struct STARTUPINFO
{
public uint cb;
public string lpReserved;
public string lpDesktop;
public string lpTitle;
public uint dwX;
public uint dwY;
public uint dwXSize;
public uint dwYSize;
public uint dwXCountChars;
public uint dwYCountChars;
public uint dwFillAttribute;
public uint dwFlags;
public ushort wShowWindow;
public ushort cbReserved2;
public IntPtr lpReserved2;
public IntPtr hStdInput;
public IntPtr hStdOutput;
public IntPtr hStdError;
}
[StructLayout(LayoutKind.Sequential)]
private struct PROCESS_INFORMATION
{
public IntPtr hProcess;
public IntPtr hThread;
public uint dwProcessId;
public uint dwThreadId;
}
[DllImport(
"kernel32.dll",
CharSet = CharSet.Unicode,
ExactSpelling = true,
SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool CreateProcessW(
string applicationName,
StringBuilder commandLine,
IntPtr processAttributes,
IntPtr threadAttributes,
[MarshalAs(UnmanagedType.Bool)] bool inheritHandles,
uint creationFlags,
IntPtr environment,
string currentDirectory,
ref STARTUPINFO startupInfo,
out PROCESS_INFORMATION processInformation);
[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool GenerateConsoleCtrlEvent(
uint ctrlEvent,
uint processGroupId);
[DllImport("kernel32.dll", SetLastError = true)]
private static extern uint GetConsoleCP();
[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool AllocConsole();
[DllImport("kernel32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool CloseHandle(IntPtr handle);
private static void EnsureConsole()
{
if (GetConsoleCP() != 0 || AllocConsole())
{
return;
}
var error = Marshal.GetLastWin32Error();
if (error != ERROR_ACCESS_DENIED || GetConsoleCP() == 0)
{
throw new Win32Exception(error);
}
}
public static Process Start(string path)
{
EnsureConsole();
var startupInfo = new STARTUPINFO {
cb = (uint)Marshal.SizeOf<STARTUPINFO>()
};
var commandLine = new StringBuilder("\"" + path + "\"");
PROCESS_INFORMATION processInformation;
if (!CreateProcessW(
path,
commandLine,
IntPtr.Zero,
IntPtr.Zero,
false,
CREATE_NEW_PROCESS_GROUP,
IntPtr.Zero,
null,
ref startupInfo,
out processInformation))
{
throw new Win32Exception(Marshal.GetLastWin32Error());
}
try
{
return Process.GetProcessById((int)processInformation.dwProcessId);
}
finally
{
CloseHandle(processInformation.hThread);
CloseHandle(processInformation.hProcess);
}
}
public static void SendCtrlBreak(int processGroupId)
{
if (!GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, (uint)processGroupId))
{
throw new Win32Exception(Marshal.GetLastWin32Error());
}
}
}
'@
$filename = [System.IO.Path]::GetFileName($binary)
$checksumLine = Get-Content $checksumFile |
Where-Object { $_ -match "\s$([regex]::Escape($filename))$" }
if (-not $checksumLine) { throw "missing checksum" }
$expectedHash = ($checksumLine -split "\s+")[0].ToLowerInvariant()
$beforeHash = (Get-FileHash -Algorithm SHA256 $binary).Hash.ToLowerInvariant()
if ($beforeHash -ne $expectedHash) { throw "checksum mismatch before execution" }
& $binary help | Out-Null
if ($LASTEXITCODE -ne 0) { throw "help failed" }
$dataDir = Join-Path $env:RUNNER_TEMP "gpt-load-native-smoke-$([guid]::NewGuid())"
New-Item -ItemType Directory -Path $dataDir | Out-Null
$env:DATA_DIR = $dataDir
$env:PORT = $port
$process = [ReleaseNativeProcess]::Start($binary)
try {
$health = $null
for ($attempt = 0; $attempt -lt 80; $attempt++) {
try {
$health = Invoke-RestMethod "http://127.0.0.1:$port/health"
break
} catch {
Start-Sleep -Milliseconds 250
}
}
if ($null -eq $health) { throw "health check timed out" }
if ($health.version -ne $releaseVersion) { throw "version mismatch" }
$authFile = Join-Path $dataDir "auth.key"
$encryptionFile = Join-Path $dataDir "encryption.key"
$databaseFile = Join-Path $dataDir "gpt-load.db"
foreach ($file in @($authFile, $encryptionFile, $databaseFile)) {
if (-not (Test-Path $file)) { throw "missing generated asset: $file" }
}
$currentSid = [System.Security.Principal.WindowsIdentity]::GetCurrent().User
foreach ($file in @($authFile, $encryptionFile)) {
$acl = Get-Acl $file
if (-not $acl.AreAccessRulesProtected) { throw "credential DACL inherits rules" }
$allowRules = @($acl.Access | Where-Object {
$_.AccessControlType -eq [System.Security.AccessControl.AccessControlType]::Allow
})
if ($allowRules.Count -eq 0) { throw "credential DACL has no allow rule" }
foreach ($rule in $allowRules) {
$sid = $rule.IdentityReference.Translate(
[System.Security.Principal.SecurityIdentifier]
)
if ($sid.Value -ne $currentSid.Value) {
throw "credential DACL allows another principal"
}
}
}
$authKey = (Get-Content $authFile -Raw).Trim()
Invoke-WebRequest "http://127.0.0.1:$port/" -UseBasicParsing | Out-Null
$headers = @{ Authorization = "Bearer $authKey" }
Invoke-RestMethod "http://127.0.0.1:$port/api/usage?range=24h" -Headers $headers | Out-Null
Invoke-RestMethod "http://127.0.0.1:$port/api/model-prices" -Headers $headers | Out-Null
[ReleaseNativeProcess]::SendCtrlBreak($process.Id)
if (-not $process.WaitForExit(15000)) {
throw "graceful shutdown timed out"
}
if ($process.ExitCode -ne 0) {
throw "graceful shutdown exited with code $($process.ExitCode)"
}
$afterHash = (Get-FileHash -Algorithm SHA256 $binary).Hash.ToLowerInvariant()
if ($afterHash -ne $expectedHash) { throw "checksum mismatch after execution" }
} finally {
# Stop-Process is failure cleanup only; success is proven by CTRL_BREAK and exit code 0.
if (-not $process.HasExited) {
Stop-Process -Id $process.Id -ErrorAction SilentlyContinue
$process.WaitForExit(5000) | Out-Null
}
Remove-Item -Recurse -Force $dataDir -ErrorAction SilentlyContinue
}
+70
View File
@@ -0,0 +1,70 @@
#!/usr/bin/env bash
set -euo pipefail
umask 077
binary="${RELEASE_SMOKE_BINARY:?RELEASE_SMOKE_BINARY is required}"
checksum_file="${RELEASE_SMOKE_CHECKSUM_FILE:?RELEASE_SMOKE_CHECKSUM_FILE is required}"
release_version="${RELEASE_VERSION:?RELEASE_VERSION is required}"
port="${RELEASE_SMOKE_PORT:-39113}"
filename="$(basename "${binary}")"
expected_hash="$(awk -v name="${filename}" '$2 == name {print $1}' "${checksum_file}")"
test -n "${expected_hash}"
if command -v sha256sum >/dev/null 2>&1; then
before_hash="$(sha256sum "${binary}" | awk '{print $1}')"
else
before_hash="$(shasum -a 256 "${binary}" | awk '{print $1}')"
fi
test "${before_hash}" = "${expected_hash}"
chmod +x "${binary}"
"${binary}" help >/dev/null
data_dir="$(mktemp -d)"
log_file="$(mktemp)"
pid=
cleanup() {
if [[ -n "${pid}" ]]; then
kill -TERM "${pid}" >/dev/null 2>&1 || true
wait "${pid}" >/dev/null 2>&1 || true
fi
rm -rf "${data_dir}" "${log_file}"
}
trap cleanup EXIT
DATA_DIR="${data_dir}" \
PORT="${port}" \
"${binary}" >"${log_file}" 2>&1 &
pid=$!
for _ in $(seq 1 80); do
if curl -fsS "http://127.0.0.1:${port}/health" >"${data_dir}/health.json"; then
break
fi
sleep 0.25
done
test -s "${data_dir}/health.json"
test -f "${data_dir}/auth.key"
test -f "${data_dir}/encryption.key"
test -f "${data_dir}/gpt-load.db"
auth_key="$(cat "${data_dir}/auth.key")"
test -n "${auth_key}"
grep -F "\"version\":\"${release_version}\"" "${data_dir}/health.json"
curl -fsS "http://127.0.0.1:${port}/" | grep -F '<div id="app"></div>' >/dev/null
curl -fsS \
-H "Authorization: Bearer ${auth_key}" \
"http://127.0.0.1:${port}/api/usage?range=24h" >/dev/null
curl -fsS \
-H "Authorization: Bearer ${auth_key}" \
"http://127.0.0.1:${port}/api/model-prices" >/dev/null
kill -TERM "${pid}"
wait "${pid}"
pid=
if command -v sha256sum >/dev/null 2>&1; then
after_hash="$(sha256sum "${binary}" | awk '{print $1}')"
else
after_hash="$(shasum -a 256 "${binary}" | awk '{print $1}')"
fi
test "${after_hash}" = "${expected_hash}"