Files
coder/enterprise/cli/boundary.go
T
Yevhenii Shcherbina 9b14fd3adc feat: add boundary premium feature (#21589)
Source code changes:

- Added a wrapper for the boundary subcommand that checks feature
entitlement before executing the underlying command.
- Added a helper that returns the Boundary version using the
runtime/debug package, which reads this information from the go.mod
file.
- Added FeatureBoundary to the corresponding enum.
- Move boundary command from AGPL to enterprise.

`NOTE`: From now on, the Boundary version will be specified in go.mod
instead of being defined in AI modules.
2026-01-23 12:56:36 -05:00

87 lines
2.4 KiB
Go

package cli
import (
"net/http"
"os"
"runtime/debug"
"golang.org/x/xerrors"
boundarycli "github.com/coder/boundary/cli"
"github.com/coder/coder/v2/codersdk"
"github.com/coder/serpent"
)
func isChild() bool {
return os.Getenv("CHILD") == "true"
}
func getBoundaryVersion() string {
const boundaryModulePath = "github.com/coder/boundary"
buildInfo, ok := debug.ReadBuildInfo()
if !ok {
return "unknown"
}
for _, module := range buildInfo.Deps {
if module.Path == boundaryModulePath {
return module.Version
}
}
return "unknown"
}
func (r *RootCmd) verifyLicense(inv *serpent.Invocation) error {
client, err := r.InitClient(inv)
if err != nil {
return err
}
entitlements, err := client.Entitlements(inv.Context())
if cerr, ok := codersdk.AsError(err); ok && cerr.StatusCode() == http.StatusNotFound {
return xerrors.Errorf("your deployment appears to be an AGPL deployment, so you cannot use the boundary command")
} else if err != nil {
return xerrors.Errorf("failed to get entitlements: %w", err)
}
feature := entitlements.Features[codersdk.FeatureBoundary]
if feature.Entitlement == codersdk.EntitlementNotEntitled {
return xerrors.Errorf("your license is not entitled to use the boundary feature")
}
if !feature.Enabled {
// Feature is entitled but disabled (shouldn't happen for FeatureBoundary
// since it's in AlwaysEnable(), but handle it gracefully).
return xerrors.Errorf("the boundary feature is disabled in your deployment configuration")
}
return nil
}
func (r *RootCmd) boundary() *serpent.Command {
version := getBoundaryVersion()
cmd := boundarycli.BaseCommand(version) // Package coder/boundary/cli exports a "base command" designed to be integrated as a subcommand.
cmd.Use += " [args...]" // The base command looks like `boundary -- command`. Serpent adds the flags piece, but we need to add the args.
// Wrap the handler to check for FeatureBoundary entitlement.
originalHandler := cmd.Handler
cmd.Handler = func(inv *serpent.Invocation) error {
// Boundary re-executes itself with CHILD=true to run the target process
// inside a jailed network namespace. Skip the license check for child
// processes since the parent already verified entitlement.
if isChild() {
return originalHandler(inv)
}
if err := r.verifyLicense(inv); err != nil {
return err
}
// Call the original handler if entitlement check passes.
return originalHandler(inv)
}
return cmd
}