diff --git a/codefly.go b/codefly.go index 819cd81..e6a115c 100644 --- a/codefly.go +++ b/codefly.go @@ -237,15 +237,10 @@ func ServiceVersion() string { return os.Getenv(resources.VersionPrefix) } -// Fixture returns the fixture selected by the Codefly runtime. Product code -// must not depend on the runtime's environment-variable representation. -func Fixture() FixtureSelection { - return FixtureSelection(os.Getenv(resources.FixturePrefix)) -} - -func WithFixture(fixture string) bool { - return resources.Match(string(Fixture()), fixture) -} +// The fixture API moved to the sdk-go/fixture package: it was the only thing in +// this root package that needed core/composition, and composition carries a +// GitHub release resolver, so every service importing codefly for its own +// address linked a GitHub API client it never calls. Use fixture.Selected(). // Environment returns the Codefly environment selected for this process. The // representation is owned by the SDK; product code must not read its carrier. diff --git a/codefly_test.go b/codefly_test.go index 049b53b..20d84f3 100644 --- a/codefly_test.go +++ b/codefly_test.go @@ -305,8 +305,8 @@ func TestWorkspaceConfigurationUsesSDKBoundary(t *testing.T) { _, err = codefly.For(ctx).WorkspaceValue("security", "missing") assert.Error(t, err) assert.True(t, codefly.IsLocal()) - assert.Equal(t, "dogfood", string(codefly.Fixture())) - assert.True(t, codefly.WithFixture("dogfood")) + // The fixture API moved to sdk-go/fixture, so it is covered there; this + // test keeps the rest of the runtime identity it was always about. assert.Equal(t, "scoped", codefly.ScopedAuthSecret()) } diff --git a/fixture.go b/fixture/fixture.go similarity index 73% rename from fixture.go rename to fixture/fixture.go index bd83c86..4737619 100644 --- a/fixture.go +++ b/fixture/fixture.go @@ -1,4 +1,13 @@ -package codefly +// Package fixture resolves the fixture the Codefly runtime selected against the +// manifests of the packages the workspace composes. +// +// It lives OUT of sdk-go's root package deliberately. It is the only thing in +// the root that needed core/composition, and composition carries a GitHub +// release resolver — so every service that imported `codefly` for its own +// address linked a GitHub API client and an HTTP artifact downloader it never +// calls. Resolving a seeded identity by role is a TEST-time concern; a service +// binary has no business carrying the code that downloads release artifacts. +package fixture import ( "context" @@ -12,11 +21,11 @@ import ( "github.com/codefly-dev/core/resources" ) -// FixtureSelection is the fixture the Codefly runtime selected for this +// Selection is the fixture the Codefly runtime selected for this // process. It resolves against the manifests of the packages the workspace // composes, so a test authenticates as a seeded identity by role instead of // hardcoding one. -type FixtureSelection string +type Selection string // Principal returns the identity the selected fixture seeds for role. Resolving // by role means a renamed or dropped principal fails here, against the package @@ -27,7 +36,7 @@ type FixtureSelection string // is invisible here: an unresolved name reports those modules, and a name that // a local module also declares resolves to the local one without reporting the // ambiguity. -func (fixture FixtureSelection) Principal(ctx context.Context, role string) (*composition.FixturePrincipal, error) { +func (fixture Selection) Principal(ctx context.Context, role string) (*composition.FixturePrincipal, error) { name := strings.TrimSpace(string(fixture)) if name == "" { return nil, errors.New("resolve fixture principal: no fixture is selected") @@ -96,3 +105,14 @@ func composedPackages(ctx context.Context) ([]*composition.PackageManifest, []st } return manifests, pinned, nil } + +// Selected is the fixture the Codefly runtime chose for this process. Product +// code must not depend on the runtime's environment-variable representation. +func Selected() Selection { + return Selection(os.Getenv(resources.FixturePrefix)) +} + +// With reports whether the selected fixture matches name. +func With(name string) bool { + return resources.Match(string(Selected()), name) +} diff --git a/fixture_test.go b/fixture/fixture_test.go similarity index 86% rename from fixture_test.go rename to fixture/fixture_test.go index e8125d0..6f39666 100644 --- a/fixture_test.go +++ b/fixture/fixture_test.go @@ -1,12 +1,13 @@ -package codefly_test +package fixture_test import ( + "os" "path/filepath" "testing" "github.com/codefly-dev/core/composition" "github.com/codefly-dev/core/resources" - codefly "github.com/codefly-dev/sdk-go" + "github.com/codefly-dev/sdk-go/fixture" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -53,7 +54,7 @@ func TestFixturePrincipalResolvesByRole(t *testing.T) { composingWorkspace(t) t.Setenv(resources.FixturePrefix, "dev-admin") - principal, err := codefly.Fixture().Principal(t.Context(), "super_admin") + principal, err := fixture.Selected().Principal(t.Context(), "super_admin") require.NoError(t, err) assert.Equal(t, "dev-admin", principal.ID) @@ -65,7 +66,7 @@ func TestFixturePrincipalUnknownRoleNamesSeededRoles(t *testing.T) { composingWorkspace(t) t.Setenv(resources.FixturePrefix, "dev-admin") - _, err := codefly.Fixture().Principal(t.Context(), "owner") + _, err := fixture.Selected().Principal(t.Context(), "owner") require.ErrorIs(t, err, composition.ErrUnknownPrincipal) assert.Contains(t, err.Error(), "super_admin, member") @@ -75,7 +76,7 @@ func TestFixturePrincipalUnknownFixtureNamesAvailableFixtures(t *testing.T) { composingWorkspace(t) t.Setenv(resources.FixturePrefix, "typo") - _, err := codefly.Fixture().Principal(t.Context(), "super_admin") + _, err := fixture.Selected().Principal(t.Context(), "super_admin") require.ErrorIs(t, err, composition.ErrUnknownFixture) assert.Contains(t, err.Error(), "dev-admin") @@ -85,7 +86,7 @@ func TestFixturePrincipalWithoutSelectedFixture(t *testing.T) { composingWorkspace(t) t.Setenv(resources.FixturePrefix, "") - _, err := codefly.Fixture().Principal(t.Context(), "super_admin") + _, err := fixture.Selected().Principal(t.Context(), "super_admin") require.Error(t, err) assert.Contains(t, err.Error(), "no fixture is selected") @@ -100,7 +101,7 @@ func TestFixturePrincipalResolvesWhenOneDirectoryIsReferencedTwice(t *testing.T) t.Chdir(root) t.Setenv(resources.FixturePrefix, "dev-admin") - principal, err := codefly.Fixture().Principal(t.Context(), "super_admin") + principal, err := fixture.Selected().Principal(t.Context(), "super_admin") require.NoError(t, err) assert.Equal(t, "dev-admin", principal.ID) @@ -113,7 +114,7 @@ func TestFixturePrincipalNamesPinnedModulesItCannotRead(t *testing.T) { t.Chdir(root) t.Setenv(resources.FixturePrefix, "dev-admin") - _, err := codefly.Fixture().Principal(t.Context(), "super_admin") + _, err := fixture.Selected().Principal(t.Context(), "super_admin") require.ErrorIs(t, err, composition.ErrUnknownFixture) // The MODULE NAME and the fact that it is pinned, not merely some @@ -130,3 +131,9 @@ func TestFixturePrincipalNamesPinnedModulesItCannotRead(t *testing.T) { "and must say that it is PINNED, which is the diagnosis: an unknown-fixture "+ "error here has meant a pinned module the SDK never read, not a wrong name") } + +func writeFile(t *testing.T, path string, content string) { + t.Helper() + require.NoError(t, os.MkdirAll(filepath.Dir(path), 0o755)) + require.NoError(t, os.WriteFile(path, []byte(content), 0o600)) +}