feat: ship single-file run distribution and list key reset

Compile-time run auth replaces zip sidecars, lengthens run keys, revokes
active sessions on reset, and exposes run-key reset in the server list.
This commit is contained in:
npc0-hue
2026-07-24 14:14:26 +08:00
parent 2b1f553df0
commit 292b380f3c
17 changed files with 397 additions and 9 deletions
+1
View File
@@ -116,6 +116,7 @@ type DistributionBuildInput struct {
TargetOS string
TargetArch string
TargetRelease string
PlatformURL string
PackageFormat string
RepositoryURL string
SourceRevision string
+2
View File
@@ -153,6 +153,7 @@ type DistributionBuildInputResponse struct {
TargetOS string `json:"targetOs"`
TargetArch string `json:"targetArch"`
TargetRelease string `json:"targetRelease"`
PlatformURL string `json:"platformUrl,omitempty"`
PackageFormat string `json:"packageFormat"`
RepositoryURL string `json:"repositoryUrl,omitempty"`
SourceRevision string `json:"sourceRevision,omitempty"`
@@ -468,6 +469,7 @@ func DistributionBuildInputFromDomain(input domain.DistributionBuildInput) Distr
TargetOS: input.TargetOS,
TargetArch: input.TargetArch,
TargetRelease: input.TargetRelease,
PlatformURL: input.PlatformURL,
PackageFormat: input.PackageFormat,
RepositoryURL: input.RepositoryURL,
SourceRevision: input.SourceRevision,
+8
View File
@@ -250,6 +250,12 @@ func distributionPackageFilename(base string, targetOS string, targetArch string
if arch != "" {
name += "-" + arch
}
if format == "raw-executable" {
if os == "windows" {
return name + ".exe"
}
return name
}
if format == "" {
format = "bin"
}
@@ -262,6 +268,8 @@ func packageContentType(packageFormat string) string {
return "application/zip"
case "tar.gz", "tgz":
return "application/gzip"
case "raw-executable":
return "application/octet-stream"
default:
return "application/octet-stream"
}
+43
View File
@@ -210,6 +210,49 @@ func (svc *CoreService) currentRunSession(runEndpointID string, sessionToken str
return domain.CopyRunControlSession(session), nil
}
func (svc *CoreService) revokeRunControlSessionForInstance(instance domain.ServerInstance) error {
if strings.TrimSpace(instance.RunEndpointID) == "" {
return nil
}
svc.controlMu.Lock()
defer svc.controlMu.Unlock()
session, err := svc.store.RunControlSessions().Get(instance.RunEndpointID)
if err != nil {
if errors.Is(err, repo.ErrNotFound) {
delete(svc.runSessions, instance.RunEndpointID)
return nil
}
return err
}
if session.Status == domain.AuthSessionStatusActive {
stamp := svc.now()
session.Status = domain.AuthSessionStatusRevoked
session.RevokedAt = stamp
session.UpdatedAt = stamp
if err := validator.ValidateRunControlSession(session); err != nil {
return err
}
if err := svc.store.RunControlSessions().Update(session); err != nil {
return err
}
}
delete(svc.runSessions, instance.RunEndpointID)
endpoint, err := svc.store.RunEndpoints().Get(instance.RunEndpointID)
if err != nil {
if errors.Is(err, repo.ErrNotFound) {
return nil
}
return err
}
endpoint.Status = domain.RunEndpointStatusOffline
if err := validator.ValidateRunEndpoint(endpoint); err != nil {
return err
}
return svc.store.RunEndpoints().Update(endpoint)
}
func runAuthenticationError(requireSigned bool) error {
if !requireSigned {
return validationError("sessionToken is invalid")
@@ -60,6 +60,7 @@ func (svc *CoreService) GetDistributionBuildInput(request domain.DistributionBui
TargetOS: distribution.TargetOS,
TargetArch: distribution.TargetArch,
TargetRelease: distribution.ID,
PlatformURL: runReleasePlatformURL(),
PackageFormat: distribution.PackageFormat,
ArtifactID: distribution.ArtifactID,
OutputFilename: executableFilename("run", distribution.TargetOS),
+22 -1
View File
@@ -6,6 +6,7 @@ import (
"encoding/hex"
"errors"
"fmt"
"os"
"strings"
"browser.local/platform/domain"
@@ -73,7 +74,7 @@ func (svc *CoreService) GenerateRunDistributionForSession(sessionID string, requ
RunEndpointID: instance.RunEndpointID,
TargetOS: request.TargetOS,
TargetArch: request.TargetArch,
PackageFormat: packageFormatForTarget(request.TargetOS),
PackageFormat: runPackageFormatForTarget(request.TargetOS),
BuildJobID: buildJobID,
ArtifactID: artifactID,
KeyGeneration: key.Generation,
@@ -374,6 +375,11 @@ func (svc *CoreService) ResetComponentKeyForSession(sessionID string, request do
return domain.EncryptedComponentKey{}, err
}
}
if request.ComponentKind == domain.DistributionComponentRun {
if err := svc.revokeRunControlSessionForInstance(instance); err != nil {
return domain.EncryptedComponentKey{}, err
}
}
if err := svc.recordAuditEvent(user.ID, "runtime-key.reset", "server-instance", instance.ID, domain.AuditResultSuccess, "reset "+string(request.ComponentKind)+" key; previous packages revoked"); err != nil {
return domain.EncryptedComponentKey{}, err
}
@@ -773,6 +779,9 @@ func (svc *CoreService) activeComponentKey(serverInstanceID string, kind domain.
func (svc *CoreService) createEncryptedComponentKey(serverInstanceID string, kind domain.DistributionComponentKind, componentKey string, generation int) (domain.EncryptedComponentKey, string, error) {
plainKey, err := randomToken()
if kind == domain.DistributionComponentRun {
plainKey, err = randomRunComponentKey()
}
if err != nil {
return domain.EncryptedComponentKey{}, "", err
}
@@ -1057,6 +1066,11 @@ func validatePluginTarget(plugin domain.GamePlugin, targetOS string) error {
return validationError("targetOs is not declared by plugin")
}
func runPackageFormatForTarget(targetOS string) string {
_ = targetOS
return "raw-executable"
}
func packageFormatForTarget(targetOS string) string {
if targetOS == "windows" {
return "zip"
@@ -1064,6 +1078,13 @@ func packageFormatForTarget(targetOS string) string {
return "tar.gz"
}
func runReleasePlatformURL() string {
if value := strings.TrimSpace(os.Getenv("PLATFORM_RUN_RELEASE_URL")); value != "" {
return value
}
return "https://scum.npc0.com"
}
func distributionID(prefix string, parts ...interface{}) string {
values := make([]string, 0, len(parts))
for _, part := range parts {
+53 -4
View File
@@ -35,7 +35,7 @@ func TestCoreServiceGeneratesRunDistributionWithEncryptedSingletonKey(t *testing
if err != nil {
t.Fatalf("generate run distribution: %v", err)
}
if distribution.KeyGeneration != 1 || distribution.SecretRef == "" || distribution.Status != domain.DistributionStatusBuilding || distribution.BuildJobID == "" || distribution.Checksum != "" {
if distribution.KeyGeneration != 1 || distribution.SecretRef == "" || distribution.PackageFormat != "raw-executable" || distribution.Status != domain.DistributionStatusBuilding || distribution.BuildJobID == "" || distribution.Checksum != "" {
t.Fatalf("unexpected run distribution: %+v", distribution)
}
job, err := svc.GetJob(distribution.BuildJobID)
@@ -62,6 +62,9 @@ func TestCoreServiceGeneratesRunDistributionWithEncryptedSingletonKey(t *testing
if config.AuthKey == "" || config.AuthKey == keys[0].EncryptedKey || strings.Contains(distribution.SecretRef, config.AuthKey) {
t.Fatalf("run package key leaked through metadata or was not encrypted, config=%+v key=%+v distribution=%+v", config, keys[0], distribution)
}
if len(config.AuthKey) < 80 {
t.Fatalf("expected longer run component key, got length %d", len(config.AuthKey))
}
auth, err := svc.AuthenticateComponent(domain.ComponentAuthenticationRequest{
ServerInstanceID: instance.ID,
ComponentKind: domain.DistributionComponentRun,
@@ -159,6 +162,7 @@ func TestCoreServiceRuntimeActionsGateDependenciesOnPluginPermission(t *testing.
}
func TestCoreServiceDistributionBuildRejectsPrematureSuccessAndCanRetryAfterUpload(t *testing.T) {
t.Setenv("PLATFORM_RUN_RELEASE_URL", "https://scum.npc0.com")
svc, session, instance := newDistributionTestFixture(t)
distribution, err := svc.GenerateRunDistributionForSession(session, domain.RunDistributionGenerateRequest{
ServerInstanceID: instance.ID,
@@ -185,6 +189,19 @@ func TestCoreServiceDistributionBuildRejectsPrematureSuccessAndCanRetryAfterUplo
if err != nil || !claim.HasJob || claim.Job.JobID != distribution.BuildJobID {
t.Fatalf("claim distribution build job: claim=%+v err=%v", claim, err)
}
buildInput, err := svc.GetDistributionBuildInput(domain.DistributionBuildInputRequest{
RunEndpointID: claim.Job.RunEndpointID,
SessionToken: hello.SessionToken,
JobID: claim.Job.JobID,
LeaseToken: claim.Job.LeaseToken,
Attempt: claim.Job.Attempt,
})
if err != nil {
t.Fatalf("get distribution build input: %v", err)
}
if buildInput.PlatformURL != "https://scum.npc0.com" || buildInput.PackageFormat != "raw-executable" || buildInput.AuthKey == "" || len(buildInput.AuthKey) < 80 {
t.Fatalf("expected raw executable build input with release URL and long key, got %+v", buildInput)
}
result := domain.RunJobResult{
RunEndpointID: instance.RunEndpointID,
SessionToken: hello.SessionToken,
@@ -227,14 +244,14 @@ func TestCoreServiceRunDistributionDownloadUsesTargetPackageName(t *testing.T) {
if err != nil {
t.Fatalf("generate run distribution: %v", err)
}
payload := []byte("windows zipped run package")
payload := []byte("windows raw run executable")
completeDistributionBuild(t, svc, distribution, payload)
reference, err := svc.OpenArtifactDownloadForSession(session, domain.ArtifactDownloadReferenceRequest{ArtifactID: distribution.ArtifactID})
if err != nil {
t.Fatalf("open run artifact download: %v", err)
}
if reference.Filename != "run-windows-amd64.zip" || reference.ContentType != "application/zip" {
if reference.Filename != "run-windows-amd64.exe" || reference.ContentType != "application/octet-stream" {
t.Fatalf("expected windows run package metadata, got %+v", reference)
}
@@ -275,7 +292,7 @@ func TestCoreServiceRunDistributionRetryReusesPartialArtifact(t *testing.T) {
if distribution.ID != distributionID || distribution.ArtifactID == partialArtifact.ID || distribution.Checksum != "" {
t.Fatalf("expected real binary build to ignore legacy config artifact, distribution=%+v artifact=%+v", distribution, partialArtifact)
}
if distribution.PackageFormat != "zip" || distribution.Status != domain.DistributionStatusBuilding || distribution.BuildJobID == "" {
if distribution.PackageFormat != "raw-executable" || distribution.Status != domain.DistributionStatusBuilding || distribution.BuildJobID == "" {
t.Fatalf("unexpected recovered distribution: %+v", distribution)
}
recoveredConfig := readGeneratedPackageConfig(t, svc, session, distribution.ArtifactID)
@@ -332,6 +349,17 @@ func TestCoreServiceResetRunKeyRevokesOldPackagesAndRequiresRegeneration(t *test
}
oldConfig := readGeneratedPackageConfig(t, svc, session, distribution.ArtifactID)
distribution = completeDistributionBuild(t, svc, distribution, []byte("compiled run archive before reset"))
helloRequest := validRunControlHello()
helloRequest.RunEndpointID = instance.RunEndpointID
helloRequest.RegistrationToken = oldConfig.AuthKey
helloRequest.ServerInstanceID = instance.ID
helloRequest.PluginID = instance.PluginID
helloRequest.ComponentKind = domain.DistributionComponentRun
helloRequest.KeyGeneration = oldConfig.KeyGeneration
hello, err := svc.RegisterRunHello(helloRequest)
if err != nil || !hello.Accepted {
t.Fatalf("register old run before reset: hello=%+v err=%v", hello, err)
}
reset, err := svc.ResetComponentKeyForSession(session, domain.ComponentKeyResetRequest{
ServerInstanceID: instance.ID,
@@ -343,6 +371,27 @@ func TestCoreServiceResetRunKeyRevokesOldPackagesAndRequiresRegeneration(t *test
if reset.Generation != 2 || reset.Status != domain.ComponentKeyStatusActive {
t.Fatalf("expected reset key generation 2, got %+v", reset)
}
if _, err := svc.AcceptRunHeartbeat(domain.RunControlHeartbeat{
RunEndpointID: instance.RunEndpointID,
SessionToken: hello.SessionToken,
Status: domain.RunEndpointStatusOnline,
Version: "stale-run",
Capacity: domain.RunCapacity{MaxJobs: 1},
CapabilityFingerprint: helloRequest.CapabilityReport.Fingerprint,
}); err == nil {
t.Fatal("expected reset to revoke the active run control session")
}
endpoint, err := svc.store.RunEndpoints().Get(instance.RunEndpointID)
if err != nil {
t.Fatalf("get endpoint after reset: %v", err)
}
if endpoint.Status != domain.RunEndpointStatusOffline {
t.Fatalf("expected reset endpoint to be marked offline, got %+v", endpoint)
}
endpoint.Status = domain.RunEndpointStatusOnline
if err := svc.store.RunEndpoints().Update(endpoint); err != nil {
t.Fatalf("restore endpoint for regeneration: %v", err)
}
oldDistribution, err := svc.store.RunDistributions().Get(distribution.ID)
if err != nil {
t.Fatalf("get old distribution: %v", err)
+8
View File
@@ -2401,6 +2401,14 @@ func randomToken() (string, error) {
return base64.RawURLEncoding.EncodeToString(token), nil
}
func randomRunComponentKey() (string, error) {
token := make([]byte, 64)
if _, err := rand.Read(token); err != nil {
return "", err
}
return base64.RawURLEncoding.EncodeToString(token), nil
}
func verifyPassword(hash string, password string) bool {
parts := strings.Split(hash, "$")
if len(parts) != 4 || parts[0] != "pbkdf2-sha256" {
+1 -1
View File
@@ -110,7 +110,7 @@ func ValidateRunDistribution(distribution domain.RunDistribution) error {
if distribution.KeyGeneration <= 0 {
violations = append(violations, "keyGeneration must be positive")
}
if distribution.PackageFormat != "zip" && distribution.PackageFormat != "tar.gz" {
if distribution.PackageFormat != "zip" && distribution.PackageFormat != "tar.gz" && distribution.PackageFormat != "raw-executable" {
violations = append(violations, "packageFormat is invalid")
}
if !strings.HasPrefix(distribution.SecretRef, "secret://runtime-keys/") {