oficina / home Public

Accept encoded JSON settings for CARLOS environment files

Paul Campbell pushed by paul@keymail.dev eaefda935d5214855f2154152f701c7fa0b5309a parent d1526e4
2 files changed, +60 −3
  • internal/home/runtime.go +28 −2
  • internal/home/runtime_test.go +32 −1

CI passed — run details

diff --git a/internal/home/runtime.go b/internal/home/runtime.go
index bb48e6e..d8f7b30 100644
--- a/internal/home/runtime.go
+++ b/internal/home/runtime.go
@@ -69,7 +69,10 @@ func LoadRuntime(dbPath string, logger *slog.Logger) (Runtime, error) {
sum := sha256.Sum256(pub)
cfg.keyID = hex.EncodeToString(sum[:])
cfg.keys = map[string][]byte{cfg.keyID: pub}
- rawManifest := os.Getenv("HOME_CONSUMERS")
+ rawManifest, err := exchangeJSON("HOME_CONSUMERS", 8192)
+ if err != nil {
+ return Runtime{}, err
+ }
// Sixteen pilot origins keep the exact CSP manifest within ordinary header
// limits. Production registration needs a separately reviewed scalable path.
if len(rawManifest) > 8192 || json.Unmarshal([]byte(rawManifest), &cfg.consumers) != nil || len(cfg.consumers) == 0 || len(cfg.consumers) > 16 {
@@ -95,7 +98,10 @@ func LoadRuntime(dbPath string, logger *slog.Logger) (Runtime, error) {
return Runtime{}, err
}
var encoded map[string]string
- raw := os.Getenv("HOME_ASSERTION_KEYS")
+ raw, err := exchangeJSON("HOME_ASSERTION_KEYS", 4096)
+ if err != nil {
+ return Runtime{}, err
+ }
if len(raw) > 4096 || json.Unmarshal([]byte(raw), &encoded) != nil || len(encoded) == 0 || len(encoded) > 8 {
return Runtime{}, errExchangeConfig
}
@@ -149,3 +155,23 @@ func NewRuntime(cfg Runtime, d *db.DB, logger *slog.Logger) (*App, error) {
a.runtime = &cfg
return a, nil
}
+
+// exchangeJSON accepts an explicitly encoded alternative for platforms whose
+// environment-file format cannot carry JSON quotes. Both forms together fail.
+func exchangeJSON(name string, limit int) (string, error) {
+ raw, encoded := os.Getenv(name), os.Getenv(name+"_BASE64")
+ if encoded == "" {
+ if len(raw) > limit {
+ return "", errExchangeConfig
+ }
+ return raw, nil
+ }
+ if raw != "" || len(encoded) > base64.StdEncoding.EncodedLen(limit) {
+ return "", errExchangeConfig
+ }
+ b, err := base64.StdEncoding.Strict().DecodeString(encoded)
+ if err != nil || len(b) > limit || base64.StdEncoding.EncodeToString(b) != encoded {
+ return "", errExchangeConfig
+ }
+ return string(b), nil
+}
diff --git a/internal/home/runtime_test.go b/internal/home/runtime_test.go
index 3b852de..84036af 100644
--- a/internal/home/runtime_test.go
+++ b/internal/home/runtime_test.go
@@ -13,7 +13,7 @@ import (
func runtimeEnv(t *testing.T) (string, string) {
t.Helper()
setSecretEnv(t, nil)
- for _, k := range []string{"HOME_ROLE", "HOME_ASSERTION_KEY", "HOME_ASSERTION_KEYS", "HOME_CONSUMERS", "HOME_CREDENTIAL_ORIGIN", "HOME_DIRECTORY_ORIGIN"} {
+ for _, k := range []string{"HOME_CONSUMERS_BASE64", "HOME_ASSERTION_KEYS_BASE64", "HOME_ROLE", "HOME_ASSERTION_KEY", "HOME_ASSERTION_KEYS", "HOME_CONSUMERS", "HOME_CREDENTIAL_ORIGIN", "HOME_DIRECTORY_ORIGIN"} {
t.Setenv(k, "")
}
t.Setenv("HOME_CREDENTIAL_ORIGIN", Origin)
@@ -93,3 +93,34 @@ func TestDirectoryRuntimeRefusesMalformedKeys(t *testing.T) {
}
}
}
+
+func TestRuntimeEncodedPlatformConfiguration(t *testing.T) {
+ private, keys := runtimeEnv(t)
+ t.Setenv("HOME_ROLE", "directory")
+ t.Setenv("HOME_ASSERTION_KEYS_BASE64", base64.StdEncoding.EncodeToString([]byte(keys)))
+ if _, err := LoadRuntime("directory.db", quietLogger()); err != nil {
+ t.Fatal(err)
+ }
+ t.Setenv("HOME_ASSERTION_KEYS", keys)
+ if _, err := LoadRuntime("directory.db", quietLogger()); err != errExchangeConfig {
+ t.Fatal("ambiguous keys accepted")
+ }
+ t.Setenv("HOME_ASSERTION_KEYS", "")
+ for _, bad := range []string{"%%%", base64.StdEncoding.EncodeToString([]byte(keys)) + "\n", base64.StdEncoding.EncodeToString([]byte(`{"key":null}`))} {
+ t.Setenv("HOME_ASSERTION_KEYS_BASE64", bad)
+ if _, err := LoadRuntime("directory.db", quietLogger()); err != errExchangeConfig {
+ t.Fatal("bad encoded keys accepted")
+ }
+ }
+ t.Setenv("HOME_ROLE", "credential")
+ t.Setenv("HOME_ASSERTION_KEY", private)
+ manifest := `{"directory":"https://oficina.works"}`
+ t.Setenv("HOME_CONSUMERS_BASE64", base64.StdEncoding.EncodeToString([]byte(manifest)))
+ if _, err := LoadRuntime("credential.db", quietLogger()); err != nil {
+ t.Fatal(err)
+ }
+ t.Setenv("HOME_CONSUMERS", manifest)
+ if _, err := LoadRuntime("credential.db", quietLogger()); err != errExchangeConfig {
+ t.Fatal("ambiguous manifest accepted")
+ }
+}