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
429 changes: 429 additions & 0 deletions .github/copilot-instructions.md

Large diffs are not rendered by default.

6 changes: 3 additions & 3 deletions .github/workflows/golangci-lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,14 @@ jobs:
- uses: actions/setup-go@v5
with:
go-version: '1.24.0'
cache: false
cache: true
- name: golangci-lint
uses: golangci/golangci-lint-action@v3
uses: golangci/golangci-lint-action@v8
with:
# Require: The version of golangci-lint to use.
# When `install-mode` is `binary` (default) the value can be v1.2 or v1.2.3 or `latest` to use the latest version.
# When `install-mode` is `goinstall` the value can be v1.2.3, `latest`, or the hash of a commit.
version: v1.64.8
version: v2.6.2

# Optional: working directory, useful for monorepos
# working-directory: somedir
Expand Down
146 changes: 62 additions & 84 deletions .golangci.yml
Original file line number Diff line number Diff line change
@@ -1,92 +1,70 @@
linters-settings:
gofmt:
simplify: true
goimports:
local-prefixes: github.com/Vonage/vonage-cloud-runtime-cli
gocyclo:
min-complexity: 20
cyclop:
max-complexity: 20
version: "2"

run:
timeout: 10m
issues-exit-code: 1
tests: true
skip-dirs:
- vendor
- .git
- node_modules

linters:
enable-all: true
disable:
- gochecknoglobals
- gochecknoinits
- funlen
- wsl
- lll
- exhaustivestruct
- wrapcheck
- exhaustruct
- forbidigo
- godot
- gofumpt
- depguard
- goerr113
- ifshort
- interfacebloat
- ireturn
- paralleltest
- testpackage
- varnamelen
- tagliatelle
- nlreturn
- noctx
- gomnd
- forcetypeassert
- whitespace
- gci
- scopelint
- godox
- gosec
- nestif
- mirror
- thelper
- usestdlibvars
- nosnakecase
- contextcheck
- maligned
- unconvert
- durationcheck
- usestdlibvars
- thelper
- predeclared
- maintidx
- unparam
- perfsprint
- gosmopolitan
enable:
- errcheck
- govet
- staticcheck
- unused
- ineffassign
- misspell
- goconst
- gocyclo
- cyclop
- errname
- errorlint
- gocritic
- goprintffuncname
- nilerr
- rowserrcheck
- sqlclosecheck
settings:
gocyclo:
min-complexity: 25
cyclop:
max-complexity: 25

exclusions:
rules:
- text: "Error return value of `.*Close` is not checked"
linters:
- errcheck
- text: "Error return value of `fmt.Fprint` is not checked"
linters:
- errcheck
- text: "Error return value of `fmt.Fprintf` is not checked"
linters:
- errcheck
- text: "Error return value of `fmt.Fprintln` is not checked"
linters:
- errcheck
- text: "don't use an underscore in package name"
linters:
- golint
- text: "package comment should be of the form"
linters:
- golint
- path: _test\.go
linters:
- funlen
- goconst
- dupl
- gocognit
- testifylint
- cyclop
- gocyclo
- errcheck
- path: tests/integration
linters:
- funlen
- goconst
- dupl
- cyclop
- gocyclo


issues:
exclude-rules:
- text: "don't use an underscore in package name"
linters:
- golint
- text: "package comment should be of the form"
linters:
- golint
- path: (.+)_test.go
linters:
- funlen
- goconst
- dupl
- exhaustivestruct
- gocognit
- structcheck
- testifylint
- path: tests/integration
linters:
- funlen
- goconst
- dupl
- exhaustivestruct
- structcheck
44 changes: 31 additions & 13 deletions docs/vcr_deploy.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,13 @@ instance:
entrypoint:
- node
- index.js
path-access:
"/api/public": "public"
"/api/admin": "private"
"/v1/users/*/profile": "public"
"/v1/internal/**": "private"
security:
access: private
override:
- path: "/api/public"
access: public
- path: "/v1/users/*/profile"
access: public
debug:
name: debug
application-id: 0dcbb945-cf09-4756-808a-e1873228f802
Expand All @@ -46,27 +48,43 @@ Flags can be used to override the mandatory fields, ie project name, instance na

The project will be created if it does not already exist.

#### Path Access Configuration
#### Security Configuration

The `path-access` configuration allows you to control access to specific paths in your application:
The `security` configuration allows you to control access to your application and specific paths:

- **public**: Allows public access to reach those paths
- **private**: Returns forbidden for those paths

**Default Behavior:**
If no `path-access` field is specified in your manifest, all endpoints will default to public access.
If no `security` field is specified in your manifest, all endpoints will default to public access.

**Configuration Structure:**
- `access`: Sets the default access level for all paths (either "public" or "private")
- `override`: Array of path-specific access overrides

**Wildcard Support:**
- Use `*` to match a single path segment: `/v1/users/*/settings`
- Use `**` to match multiple path segments: `/v1/**`

**Examples:**
```yaml
path-access:
"/api/health": "public" # Public health check endpoint
"/api/admin": "private" # Private admin interface
"/v1/users/*/profile": "public" # Public user profiles (wildcard)
"/v1/internal/**": "private" # All internal APIs (recursive wildcard)
# Example 1: Default public with specific private paths
security:
access: public
override:
- path: "/api/admin"
access: private
- path: "/v1/internal/**"
access: private

# Example 2: Default private with specific public paths
security:
access: private
override:
- path: "/api/health"
access: public
- path: "/v1/users/*/profile"
access: public
```


Expand Down
2 changes: 1 addition & 1 deletion main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ func Test_printError(t *testing.T) {
},
want: want{
stdout: "\n\nA new release of vcr is available: 0.0.1 → 1.0.1\nTo upgrade, run: vcr upgrade\n",
stderr: "X Error Encountered: http error\n\nℹ Details:\n - HTTP Status : 404\n - Error Code : 3001\n - Message : Not Found\n - Trace ID : 1234\n\nℹ App logs captured before failure:\ncontainer logs\n\nPlease refer to the documentation or contact support for further assistance.\n",
stderr: "X Error Encountered: http error\n\nℹ Details:\n - HTTP Status : 404\n - Message : Not Found\n - Trace ID : 1234\n\nℹ App logs captured before failure:\ncontainer logs\n\nPlease refer to the documentation or contact support for further assistance.\n",
},
},
{
Expand Down
20 changes: 10 additions & 10 deletions pkg/api/deployment.go
Original file line number Diff line number Diff line change
Expand Up @@ -240,16 +240,16 @@ func (c *DeploymentClient) CreateProject(ctx context.Context, projectName string
}

type DeployInstanceArgs struct {
PackageID string `json:"packageId"`
ProjectID string `json:"projectId"`
APIApplicationID string `json:"apiApplicationId"`
InstanceName string `json:"instanceName"`
Region string `json:"region"`
Environment []config.Env `json:"environment"`
Domains []string `json:"domains"`
MinScale int `json:"minScale"`
MaxScale int `json:"maxScale"`
PathAccess map[string]string `json:"pathAccess,omitempty"`
PackageID string `json:"packageId"`
ProjectID string `json:"projectId"`
APIApplicationID string `json:"apiApplicationId"`
InstanceName string `json:"instanceName"`
Region string `json:"region"`
Environment []config.Env `json:"environment"`
Domains []string `json:"domains"`
MinScale int `json:"minScale"`
MaxScale int `json:"maxScale"`
Security *config.Security `json:"security,omitempty"`
}

type DeployInstanceResponse struct {
Expand Down
38 changes: 23 additions & 15 deletions pkg/api/deployment_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -787,7 +787,7 @@ func TestDeployInstance(t *testing.T) {
}
}

func TestDeployInstanceWithPathAccess(t *testing.T) {
func TestDeployInstanceWithSecurity(t *testing.T) {
client := resty.New()
httpmock.ActivateNonDefault(client.GetClient())
defer httpmock.DeactivateAndReset()
Expand All @@ -813,10 +813,13 @@ func TestDeployInstanceWithPathAccess(t *testing.T) {
APIApplicationID: "test-app-id",
InstanceName: "test-instance",
Region: "test-region",
PathAccess: map[string]string{
"/api/v1": "read",
"/admin": "write",
"/public": "read-write",
Security: &config.Security{
Access: "private",
Override: []config.PathAccess{
{Path: "/api/v1", Access: "public"},
{Path: "/admin", Access: "private"},
{Path: "/public", Access: "public"},
},
},
}

Expand All @@ -828,24 +831,29 @@ func TestDeployInstanceWithPathAccess(t *testing.T) {
require.Equal(t, "test-deployment-id", output.DeploymentID)
require.Equal(t, []string{"https://test.example.com"}, output.HostURLs)

// Validate that the request body contains the PathAccess field
// Validate that the request body contains the Security field
require.NotEmpty(t, capturedRequestBody, "Request body should not be empty")

// Parse the captured request body to verify PathAccess is included
// Parse the captured request body to verify Security is included
var requestPayload map[string]interface{}
err = json.Unmarshal(capturedRequestBody, &requestPayload)
require.NoError(t, err, "Should be able to parse request body as JSON")

// Check that pathAccess field is present and correct
pathAccess, exists := requestPayload["pathAccess"]
require.True(t, exists, "pathAccess field should be present in request body")
// Check that security field is present and correct
security, exists := requestPayload["security"]
require.True(t, exists, "security field should be present in request body")

securityMap, ok := security.(map[string]interface{})
require.True(t, ok, "security should be a map")

require.Equal(t, "private", securityMap["access"])

pathAccessMap, ok := pathAccess.(map[string]interface{})
require.True(t, ok, "pathAccess should be a map")
overrides, exists := securityMap["override"]
require.True(t, exists, "override field should be present")

require.Equal(t, "read", pathAccessMap["/api/v1"])
require.Equal(t, "write", pathAccessMap["/admin"])
require.Equal(t, "read-write", pathAccessMap["/public"])
overridesArray, ok := overrides.([]interface{})
require.True(t, ok, "override should be an array")
require.Len(t, overridesArray, 3)

httpmock.Reset()
}
Expand Down
32 changes: 21 additions & 11 deletions pkg/config/manifest.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,18 +44,28 @@ type Scaling struct {
MaxScale int `yaml:"max-scale,omitempty"`
}

type Security struct {
Access string `json:"access" yaml:"access"`
Override []PathAccess `json:"override,omitempty" yaml:"override,omitempty"`
}

type PathAccess struct {
Path string `json:"path" yaml:"path"`
Access string `json:"access" yaml:"access"`
}

type Instance struct {
Name string `yaml:"name"`
Runtime string `yaml:"runtime,omitempty"`
Region string `yaml:"region,omitempty"`
ApplicationID string `yaml:"application-id,omitempty"`
Environment []Env `yaml:"environment,omitempty"`
Capabilities []string `yaml:"capabilities,omitempty"`
Entrypoint []string `yaml:"entrypoint,omitempty"`
Domains []string `yaml:"domains,omitempty"`
BuildScript string `yaml:"build-script,omitempty"`
Scaling Scaling `yaml:"scaling,omitempty"`
PathAccess map[string]string `yaml:"path-access,omitempty"`
Name string `yaml:"name"`
Runtime string `yaml:"runtime,omitempty"`
Region string `yaml:"region,omitempty"`
ApplicationID string `yaml:"application-id,omitempty"`
Environment []Env `yaml:"environment,omitempty"`
Capabilities []string `yaml:"capabilities,omitempty"`
Entrypoint []string `yaml:"entrypoint,omitempty"`
Domains []string `yaml:"domains,omitempty"`
BuildScript string `yaml:"build-script,omitempty"`
Scaling Scaling `yaml:"scaling,omitempty"`
Security *Security `yaml:"security,omitempty"`
}

type Debug struct {
Expand Down
Loading
Loading