fix(auth): make local verification portable
Keep upstream identity visible while limiting logout to local auth. Inject the restore privilege gate so the deterministic core tests do not depend on the host OS, and confine descriptor-backed projection tests to Linux. Accept the real remaining Pi timeout budget instead of an exact millisecond.
This commit is contained in:
@@ -1,3 +1,5 @@
|
||||
//go:build linux
|
||||
|
||||
package authconfig
|
||||
|
||||
import (
|
||||
|
||||
@@ -46,6 +46,7 @@ type restoreDependencies struct {
|
||||
checkpoint func(context.Context, *lifecycle.Transaction, config.Installation, CreateRequest) (Result, error)
|
||||
prepareRecovery func(context.Context, config.Installation, string) (PreflightResult, error)
|
||||
recover func(context.Context, config.Installation, PreflightResult, *stagedArchive, bool, authProjectionRestoreTransaction) error
|
||||
requireAuthProjection func() error
|
||||
beginAuthProjection func(context.Context, config.Installation) (authProjectionRestoreTransaction, error)
|
||||
cleanupCheckpoint func(string) error
|
||||
acquireTransaction func(config.Installation) (*lifecycle.Transaction, error)
|
||||
@@ -91,7 +92,7 @@ func restoreWithDependencies(ctx context.Context, installation config.Installati
|
||||
if request.Archive == "" {
|
||||
return RestoreResult{}, errors.New("restore archive is required")
|
||||
}
|
||||
if deps.preflight == nil || deps.checkpoint == nil || deps.prepareRecovery == nil || deps.recover == nil || deps.cleanupCheckpoint == nil || deps.acquireTransaction == nil || deps.runner == nil || deps.restoreFile == nil || deps.restoreVolume == nil || deps.resetAuthenticationState == nil || deps.verify == nil {
|
||||
if deps.preflight == nil || deps.checkpoint == nil || deps.prepareRecovery == nil || deps.recover == nil || deps.requireAuthProjection == nil || deps.cleanupCheckpoint == nil || deps.acquireTransaction == nil || deps.runner == nil || deps.restoreFile == nil || deps.restoreVolume == nil || deps.resetAuthenticationState == nil || deps.verify == nil {
|
||||
return RestoreResult{}, errors.New("restore dependencies are incomplete")
|
||||
}
|
||||
|
||||
@@ -117,7 +118,7 @@ func restoreWithDependencies(ctx context.Context, installation config.Installati
|
||||
defer preflight.CloseArchive()
|
||||
authRestoreRequired := installation.HasRuntimeAuthProjection() && manifestArchivesAuthentication(preflight.Manifest)
|
||||
if authRestoreRequired {
|
||||
if err := requireAuthProjectionRestorePrivilege(); err != nil {
|
||||
if err := deps.requireAuthProjection(); err != nil {
|
||||
return result, err
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,8 +49,9 @@ func productionRestoreDependencies(installation config.Installation) restoreDepe
|
||||
request.Output = path
|
||||
return createWithDependenciesTransaction(ctx, transaction, target, request, productionCreateDependencies(target))
|
||||
},
|
||||
cleanupCheckpoint: cleanupRecoveryCheckpoint,
|
||||
acquireTransaction: lifecycle.AcquireTransaction,
|
||||
cleanupCheckpoint: cleanupRecoveryCheckpoint,
|
||||
acquireTransaction: lifecycle.AcquireTransaction,
|
||||
requireAuthProjection: requireAuthProjectionRestorePrivilege,
|
||||
beginAuthProjection: func(ctx context.Context, target config.Installation) (authProjectionRestoreTransaction, error) {
|
||||
projection := target.RuntimeAuthProjection()
|
||||
if projection == nil {
|
||||
|
||||
@@ -2009,11 +2009,12 @@ func restoreTestDependencies(t *testing.T, runner archiveRunner) restoreDependen
|
||||
recover: func(context.Context, config.Installation, PreflightResult, *stagedArchive, bool, authProjectionRestoreTransaction) error {
|
||||
return nil
|
||||
},
|
||||
cleanupCheckpoint: func(string) error { return nil },
|
||||
acquireTransaction: lifecycle.AcquireTransaction,
|
||||
runner: runner,
|
||||
sleep: func(time.Duration) {},
|
||||
restoreFile: func(context.Context, config.Installation, ArchiveEntryMetadata, io.Reader) error { return nil },
|
||||
cleanupCheckpoint: func(string) error { return nil },
|
||||
acquireTransaction: lifecycle.AcquireTransaction,
|
||||
requireAuthProjection: func() error { return nil },
|
||||
runner: runner,
|
||||
sleep: func(time.Duration) {},
|
||||
restoreFile: func(context.Context, config.Installation, ArchiveEntryMetadata, io.Reader) error { return nil },
|
||||
restoreVolume: func(context.Context, config.Installation, VolumeMetadata, io.Reader) error {
|
||||
return nil
|
||||
},
|
||||
|
||||
@@ -208,6 +208,7 @@ func TestEnsureFilesRequiresExplicitNonInteractiveAnswers(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestEnsureFilesIncludesServerStorageLocations(t *testing.T) {
|
||||
requireProjectedServerTestHost(t)
|
||||
root := newProject(t, "server profile")
|
||||
setNonInteractiveAnswers(t, newExternalSecrets(t, root))
|
||||
result, err := EnsureFiles(Request{ProjectRoot: root, InstallationID: "server", Profile: "server", NonInteractive: true}, strings.NewReader(""), ioDiscard{})
|
||||
@@ -225,6 +226,13 @@ func TestEnsureFilesIncludesServerStorageLocations(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func requireProjectedServerTestHost(t *testing.T) {
|
||||
t.Helper()
|
||||
if runtime.GOOS != "linux" || os.Geteuid() != 0 {
|
||||
t.Skip("projected server filesystem integration requires Linux root")
|
||||
}
|
||||
}
|
||||
|
||||
func TestEnsureFilesProjectedServerRefusesBeforeAnyWriteWhenNotRoot(t *testing.T) {
|
||||
root := newProject(t, "projected server non-root")
|
||||
setNonInteractiveAnswers(t, newExternalSecrets(t, root))
|
||||
|
||||
@@ -101,6 +101,7 @@ func TestRunConfiguresAndStaticallyValidatesLocalAuthBeforeComposeRender(t *test
|
||||
}
|
||||
|
||||
func TestRunConfigureOnlyPublishesInitialProjectedServerAuthentication(t *testing.T) {
|
||||
requireProjectedServerTestHost(t)
|
||||
projectRoot, request := setupRunFixture(t, true)
|
||||
request.Profile = "server"
|
||||
if err := os.WriteFile(filepath.Join(projectRoot, "deploy", "compose.auth-runtime-projection.yaml"), []byte("services: {}\n"), 0o600); err != nil {
|
||||
@@ -125,6 +126,7 @@ func TestRunConfigureOnlyPublishesInitialProjectedServerAuthentication(t *testin
|
||||
}
|
||||
|
||||
func TestRunConfigureOnlyLeavesProjectedAuthenticationBlockedWhenInitialPublicationFails(t *testing.T) {
|
||||
requireProjectedServerTestHost(t)
|
||||
projectRoot, request := setupRunFixture(t, true)
|
||||
request.Profile = "server"
|
||||
if err := os.WriteFile(filepath.Join(projectRoot, "deploy", "compose.auth-runtime-projection.yaml"), []byte("services: {}\n"), 0o600); err != nil {
|
||||
@@ -162,6 +164,7 @@ func TestRunConfigureOnlyLeavesProjectedAuthenticationBlockedWhenInitialPublicat
|
||||
}
|
||||
|
||||
func TestRunConfigureOnlyVerifiesProjectedAuthenticationAfterPublication(t *testing.T) {
|
||||
requireProjectedServerTestHost(t)
|
||||
projectRoot, request := setupRunFixture(t, true)
|
||||
request.Profile = "server"
|
||||
if err := os.WriteFile(filepath.Join(projectRoot, "deploy", "compose.auth-runtime-projection.yaml"), []byte("services: {}\n"), 0o600); err != nil {
|
||||
|
||||
Reference in New Issue
Block a user