Skip to content
Merged
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
17 changes: 15 additions & 2 deletions pkg/platformhubpolicies/platform_hub_policy.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package platformhubpolicies

import (
"sync"

"github.com/go-playground/validator/v10"
"github.com/go-playground/validator/v10/non-standard/validators"
)
Expand Down Expand Up @@ -107,11 +109,22 @@ func (p *PlatformHubPolicy) SetViolationAction(violationAction string) {

// Validate checks the state of the policy and returns an error if invalid.
func (p *PlatformHubPolicy) Validate() error {
validate, err := getValidator()
if err != nil {
return err
}

return validate.Struct(p)
}

var getValidator = sync.OnceValues(buildValidator)

func buildValidator() (*validator.Validate, error) {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

will this break if someone changes something on the validator

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need pointer validator, because validator methods expect receiver to be a pointer.

I don't think there is a risk of validator being compromised

  • Validator instance is designed to be have immutable cache (didn't dig deep to confirm that)
  • Validator is private member, which can be accessed only within our package

v := validator.New()
err := v.RegisterValidation("notblank", validators.NotBlank)
if err != nil {
return err
return nil, err
}

return v.Struct(p)
return v, nil
}
96 changes: 96 additions & 0 deletions pkg/platformhubpolicies/platform_hub_policy_version_service.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
package platformhubpolicies

import (
"time"

"github.com/OctopusDeploy/go-octopusdeploy/v2/pkg/newclient"
)

// PlatformHubPolicyVersion represents an immutable published version of a Platform Hub policy.
type PlatformHubPolicyVersion struct {
ID string `json:"Id"`
Slug string `json:"Slug"`
Version string `json:"Version"`
PublishedDate time.Time `json:"PublishedDate"`
GitRef string `json:"GitRef"`
GitCommit string `json:"GitCommit"`
Name string `json:"Name"`
Description string `json:"Description,omitempty"`
ViolationReason string `json:"ViolationReason,omitempty"`
ViolationAction string `json:"ViolationAction"`
RegoScope string `json:"RegoScope"`
RegoConditions string `json:"RegoConditions"`
IsActive bool `json:"IsActive"`
}

// Publish publishes a Platform Hub policy version.
func Publish(client newclient.Client, gitRef string, slug string, version string) (PlatformHubPolicyVersion, error) {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I assume we are returning the version by value as you "can't" modify it

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, we intentionally return a data object, because policy version is immutable structure in the Octopus Deploy

path, pathError := client.URITemplateCache().Expand("/api/platformhub/{gitRef}/policies/{slug}/publish", map[string]any{"gitRef": gitRef, "slug": slug})
if pathError != nil {
return PlatformHubPolicyVersion{}, pathError
}

body := struct {
Version string `json:"Version"`
}{Version: version}

publishedVersion, err := newclient.Post[PlatformHubPolicyVersion](client.HttpSession(), path, body)
if err != nil {
return PlatformHubPolicyVersion{}, err
}

return *publishedVersion, nil
}

// VersionsQuery represents query parameters for listing policy versions.
type VersionsQuery struct {
Slug string `uri:"slug"`
Skip int `uri:"skip,omitempty"`
Take int `uri:"take,omitempty"`
}

// GetVersions returns published versions of a Platform Hub policy.
func GetVersions(client newclient.Client, query VersionsQuery) ([]PlatformHubPolicyVersion, error) {
path, pathError := client.URITemplateCache().Expand("/api/platformhub/policies/{slug}/versions{?skip,take}", query)
if pathError != nil {
return nil, pathError
}

versions, err := newclient.Get[[]PlatformHubPolicyVersion](client.HttpSession(), path)
if err != nil {
return nil, err
}

return *versions, nil
}

// ActivateVersion activates a published Platform Hub policy version.
func ActivateVersion(client newclient.Client, version PlatformHubPolicyVersion) (PlatformHubPolicyVersion, error) {
return modifyVersionStatus(client, version, true)
}

// DeactivateVersion deactivates a published Platform Hub policy version.
func DeactivateVersion(client newclient.Client, version PlatformHubPolicyVersion) (PlatformHubPolicyVersion, error) {
return modifyVersionStatus(client, version, false)
}

func modifyVersionStatus(client newclient.Client, version PlatformHubPolicyVersion, isActive bool) (PlatformHubPolicyVersion, error) {
path, pathError := client.URITemplateCache().Expand("/api/platformhub/policies/{slug}/versions/{version}/modify-status", map[string]any{
"slug": version.Slug,
"version": version.Version,
})
if pathError != nil {
return version, pathError
}

body := struct {
IsActive bool `json:"IsActive"`
}{IsActive: isActive}

modifiedVersion, err := newclient.Post[PlatformHubPolicyVersion](client.HttpSession(), path, body)
if err != nil {
return version, err
}

return *modifiedVersion, nil
}
Loading