Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions v2/client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package client
import (
"fmt"

"github.com/skyflowapi/skyflow-go/v2/internal/helpers"
"github.com/skyflowapi/skyflow-go/v2/internal/validation"
"github.com/skyflowapi/skyflow-go/v2/internal/vault/controller"
vaultutils "github.com/skyflowapi/skyflow-go/v2/utils/common"
Expand Down Expand Up @@ -37,6 +38,17 @@ func NewSkyflow(opts ...Option) (*Skyflow, *error.SkyflowError) {
}
}

sdkVersion := helpers.CurrentSDKVersion()
if helpers.IsNonGaVersion(sdkVersion) {
var vaultConfigs []vaultutils.VaultConfig
for _, svc := range client.vaultServices {
vaultConfigs = append(vaultConfigs, *svc.config)
}
if helpers.AnyVaultIsProd(vaultConfigs) {
logger.Warn(fmt.Sprintf(logs.BETA_BUILD_WARNING, sdkVersion))
}
}

logger.Info(logs.CLIENT_INITIALIZED)
return client, nil
}
Expand Down
33 changes: 33 additions & 0 deletions v2/client/client_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package client

import (
"bytes"
"fmt"
"os"
"testing"
Expand Down Expand Up @@ -2166,3 +2167,35 @@ var _ = Describe("Skyflow lifecycle: after Vault/Detect/Connection activated", f
})
})
})

// SK-2963: beta-build-in-prod warning.
//
// helpers.CurrentSDKVersion() falls back to the real, GA constants.SDK_VERSION whenever
// go test's own build info isn't a resolved module version (see helpers_test.go's
// "CurrentSDKVersion" spec) - so unlike a real beta-tagged consumer, NewSkyflow() in this
// suite can never actually take the "non-GA" branch. The logic that decides *whether* to
// warn (IsNonGaVersion, AnyVaultIsProd) is covered directly in helpers_test.go; this only
// proves the real wiring stays silent against today's real GA build, which is what every
// test run actually exercises.
var _ = Describe("Beta build warning wiring", func() {
var buf bytes.Buffer

BeforeEach(func() {
buf.Reset()
logger.SetOutput(&buf)
logger.SetLogLevel(logger.WARN)
})
AfterEach(func() {
logger.SetOutput(os.Stderr)
logger.SetLogLevel(logger.ERROR)
})

It("does not warn for the real GA build even against a PROD vault", func() {
_, err := NewSkyflow(
WithLogLevel(logger.WARN),
WithVaults(common.VaultConfig{VaultId: "v1", ClusterId: "cluster1", Env: common.PROD}),
)
Expect(err).To(BeNil())
Expect(buf.String()).ToNot(ContainSubstring("beta/pre-release build"))
})
})
58 changes: 58 additions & 0 deletions v2/internal/helpers/helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import (
"os"
"regexp"
"runtime"
"runtime/debug"
"time"

"github.com/skyflowapi/skyflow-go/v2/internal/generated/core"
Expand Down Expand Up @@ -314,6 +315,63 @@ func GetURLWithEnv(env common.Env, clusterId string) string {
return url
}

// gaVersionPattern matches a clean public release (e.g. "v2.1.0"); anything else -
// "v2.1.0-beta.1", "v2.1.0-dev.abc1234" - is a non-GA build.
var gaVersionPattern = regexp.MustCompile(`^v?\d+\.\d+\.\d+$`)

// IsNonGaVersion reports whether version is a beta/dev pre-release build rather than a
// plain public release.
func IsNonGaVersion(version string) bool {
return !gaVersionPattern.MatchString(version)
}

// AnyVaultIsProd reports whether any of the given vault configs resolves to Env.PROD.
// PROD is Env's zero value (see utils/common.Env), so an unset Env already defaults to
// it, same as GetURLWithEnv's own default case above.
func AnyVaultIsProd(vaultConfigs []common.VaultConfig) bool {
for _, vaultConfig := range vaultConfigs {
if vaultConfig.Env == common.PROD {
return true
}
}
return false
}

// skyflowGoModulePath must match the module directive in go.mod.
const skyflowGoModulePath = "github.com/skyflowapi/skyflow-go/v2"

// develVersion is what debug.ReadBuildInfo() reports for Main.Version when the binary
// wasn't built as a proper versioned module dependency (e.g. `go test` run against this
// module's own source, or a local `go build` from within it) - not a meaningful version.
const develVersion = "(devel)"

// CurrentSDKVersion returns the version of this module as actually resolved by the
// importing consumer's go.mod (e.g. "v2.1.0-beta.1"), read from the running binary's
// embedded build info. constants.SDK_VERSION is a manually maintained literal that isn't
// bumped per release (see internal/constants/constants.go), so on its own it can't be
// trusted to detect a beta/dev build - this reads the ground truth instead, falling back
// to the constant when build info isn't meaningful (e.g. `go test` against this module's
// own source, where Main.Version is always "(devel)", see develVersion below).
func CurrentSDKVersion() string {
info, ok := debug.ReadBuildInfo()
if !ok {
return constants.SDK_VERSION
}
if info.Main.Path == skyflowGoModulePath && isResolvedVersion(info.Main.Version) {
return info.Main.Version
}
for _, dep := range info.Deps {
if dep.Path == skyflowGoModulePath && isResolvedVersion(dep.Version) {
return dep.Version
}
}
return constants.SDK_VERSION
}

func isResolvedVersion(version string) bool {
return version != "" && version != develVersion
}

func ParseTokenizeResponse(apiResponse vaultapis.V1TokenizeResponse) *common.TokenizeResponse {
var tokens []string
for _, record := range apiResponse.GetRecords() {
Expand Down
54 changes: 54 additions & 0 deletions v2/internal/helpers/helpers_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (

. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
constants "github.com/skyflowapi/skyflow-go/v2/internal/constants"
vaultapis "github.com/skyflowapi/skyflow-go/v2/internal/generated"
"github.com/skyflowapi/skyflow-go/v2/internal/generated/core"
. "github.com/skyflowapi/skyflow-go/v2/internal/helpers"
Expand Down Expand Up @@ -1867,3 +1868,56 @@ var _ = Describe("Deprecation warning logs", func() {
})
})
})

// SK-2963: beta-build-in-prod warning.
var _ = Describe("IsNonGaVersion", func() {
It("treats a plain semver release as GA", func() {
Expect(IsNonGaVersion("v2.1.0")).To(BeFalse())
Expect(IsNonGaVersion("2.11.3")).To(BeFalse())
})
It("treats a beta suffix as non-GA", func() {
Expect(IsNonGaVersion("v2.1.0-beta.1")).To(BeTrue())
})
It("treats a dev suffix as non-GA", func() {
Expect(IsNonGaVersion("v2.1.0-dev.abc1234")).To(BeTrue())
})
It("treats an empty or garbage string as non-GA", func() {
Expect(IsNonGaVersion("")).To(BeTrue())
Expect(IsNonGaVersion("not-a-version")).To(BeTrue())
})
})

var _ = Describe("AnyVaultIsProd", func() {
It("returns false for an empty list", func() {
Expect(AnyVaultIsProd(nil)).To(BeFalse())
Expect(AnyVaultIsProd([]common.VaultConfig{})).To(BeFalse())
})
It("returns false when no vault is PROD", func() {
configs := []common.VaultConfig{
{VaultId: "v1", Env: common.DEV},
{VaultId: "v2", Env: common.SANDBOX},
{VaultId: "v3", Env: common.STAGE},
}
Expect(AnyVaultIsProd(configs)).To(BeFalse())
})
It("returns true when one of several vaults is PROD", func() {
configs := []common.VaultConfig{
{VaultId: "v1", Env: common.DEV},
{VaultId: "v2", Env: common.PROD},
}
Expect(AnyVaultIsProd(configs)).To(BeTrue())
})
It("treats an unset Env as PROD, matching GetURLWithEnv's own default", func() {
configs := []common.VaultConfig{{VaultId: "v1"}}
Expect(AnyVaultIsProd(configs)).To(BeTrue())
})
})

var _ = Describe("CurrentSDKVersion", func() {
It("falls back to constants.SDK_VERSION when build info isn't a resolved module version", func() {
// go test builds this module's own source, so debug.ReadBuildInfo().Main.Version
// is always "(devel)" here - this exercises (and documents) the fallback path;
// the real-consumer path can only be exercised by an actual downstream module.
Expect(CurrentSDKVersion()).To(Equal(constants.SDK_VERSION))
})
})
2 changes: 2 additions & 0 deletions v2/utils/messages/info_logs.go
Original file line number Diff line number Diff line change
Expand Up @@ -105,4 +105,6 @@ const (
DEPRECATED_RESPONSE_KEY_SKYFLOW_ID_UPDATE = SDK_LOG_PREFIX + "Deprecated: response key 'skyflowId' is deprecated and will be removed in a future version. Use 'SkyflowId' instead."
DEPRECATED_RESPONSE_KEY_TOKENIZED_DATA = SDK_LOG_PREFIX + "Deprecated: response key 'tokenized_data' is deprecated and will be removed in a future version. Use 'TokenizedData' instead."
DEPRECATED_FIELD_REQUEST_INDEX = SDK_LOG_PREFIX + "Deprecated: field 'request_index' is deprecated and will be removed in a future version. Use 'RequestIndex' instead."

BETA_BUILD_WARNING = SDK_LOG_PREFIX + "This is a beta/pre-release build of the Skyflow SDK (%s). Beta builds are intended for acceptance testing only - you appear to be connecting to a Production vault. Contact your Skyflow representative before using this build in Production."
)
Loading