diff --git a/apis/refs/v1beta1/privatecaref.go b/apis/refs/v1beta1/privatecaref.go new file mode 100644 index 0000000000..9c880c7362 --- /dev/null +++ b/apis/refs/v1beta1/privatecaref.go @@ -0,0 +1,112 @@ +// Copyright 2024 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package v1beta1 + +import ( + "context" + "fmt" + "strings" + + apierrors "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/apimachinery/pkg/types" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +type PrivateCACAPoolRef struct { + // A reference to an externally managed PrivateCACAPool. + // Should be in the format `projects/{project_id}/locations/{region}/caPools/{caPool}`. + External string `json:"external,omitempty"` + + // The `name` of a `PrivateCACAPool` resource. + Name string `json:"name,omitempty"` + // The `namespace` of a `PrivateCACAPool` resource. + Namespace string `json:"namespace,omitempty"` +} + +type PrivateCACAPool struct { + Ref *PrivateCACAPoolRef + ResourceID string +} + +// ResolvePrivateCACAPoolRef will resolve a PrivateCACAPoolRef to a PrivateCACAPool. +func ResolvePrivateCACAPoolRef(ctx context.Context, reader client.Reader, src client.Object, ref *PrivateCACAPoolRef) (*PrivateCACAPoolRef, error) { + if ref == nil { + return nil, nil + } + + if ref.Name == "" && ref.External == "" { + return nil, fmt.Errorf("must specify either name or external on PrivateCACAPoolRef") + } + if ref.Name != "" && ref.External != "" { + return nil, fmt.Errorf("cannot specify both name and external on PrivateCACAPoolRef") + } + + // External should be in the `projects/{project_id}/locations/{region}/caPools/{caPool}` format + if ref.External != "" { + tokens := strings.Split(ref.External, "/") + if len(tokens) == 6 && tokens[0] == "projects" && tokens[2] == "locations" && tokens[4] == "caPools" { + ref = &PrivateCACAPoolRef{ + External: fmt.Sprintf("projects/%s/locations/%s/caPools/%s", tokens[1], tokens[3], tokens[5]), + } + return ref, nil + } + return nil, fmt.Errorf("format of PrivateCACAPoolRef external=%q was not known (use projects/{project_id}/locations/{region}/caPools/{caPool})", ref.External) + } + + key := types.NamespacedName{ + Namespace: ref.Namespace, + Name: ref.Name, + } + if key.Namespace == "" { + key.Namespace = src.GetNamespace() + } + + // Fetch object from k8s cluster to construct the external form + caPool := &unstructured.Unstructured{} + caPool.SetGroupVersionKind(schema.GroupVersionKind{ + Group: "privateca.cnrm.cloud.google.com", + Version: "v1beta1", + Kind: "PrivateCACAPool", + }) + if err := reader.Get(ctx, key, caPool); err != nil { + if apierrors.IsNotFound(err) { + return nil, fmt.Errorf("referenced PrivateCACAPool %v not found", key) + } + return nil, fmt.Errorf("error reading referenced PrivateCACAPool %v: %w", key, err) + } + + caPoolResourceID, err := GetResourceID(caPool) + if err != nil { + return nil, err + } + + projectID, err := ResolveProjectID(ctx, reader, caPool) + if err != nil { + return nil, err + } + + location, err := GetLocation(caPool) + if err != nil { + return nil, err + } + + ref = &PrivateCACAPoolRef{ + External: fmt.Sprintf("projects/%s/locations/%s/caPools/%s", projectID, location, caPoolResourceID), + } + + return ref, nil +} diff --git a/apis/securesourcemanager/v1alpha1/instance_types.go b/apis/securesourcemanager/v1alpha1/instance_types.go index 474a81c48a..b96d13541c 100644 --- a/apis/securesourcemanager/v1alpha1/instance_types.go +++ b/apis/securesourcemanager/v1alpha1/instance_types.go @@ -44,6 +44,9 @@ type SecureSourceManagerInstanceSpec struct { // Optional. Immutable. Customer-managed encryption key name. KmsKeyRef *refs.KMSCryptoKeyRef `json:"kmsKeyRef,omitempty"` + + // Optional. PrivateConfig includes settings for private instance. + PrivateConfig *Instance_PrivateConfig `json:"privateConfig,omitempty"` } // SecureSourceManagerInstanceStatus defines the config connector machine state of SecureSourceManagerInstance diff --git a/apis/securesourcemanager/v1alpha1/types.generated.go b/apis/securesourcemanager/v1alpha1/types.generated.go index 1a337c862e..1547d1c922 100644 --- a/apis/securesourcemanager/v1alpha1/types.generated.go +++ b/apis/securesourcemanager/v1alpha1/types.generated.go @@ -14,6 +14,10 @@ package v1alpha1 +import ( + refs "github.com/GoogleCloudPlatform/k8s-config-connector/apis/refs/v1beta1" +) + // +kcc:proto=google.cloud.securesourcemanager.v1.Instance.HostConfig type Instance_HostConfig struct { // Output only. HTML hostname. @@ -37,7 +41,7 @@ type Instance_PrivateConfig struct { // Required. Immutable. CA pool resource, resource must in the format of // `projects/{project}/locations/{location}/caPools/{ca_pool}`. - CaPool *string `json:"caPool,omitempty"` + CaPoolRef *refs.PrivateCACAPoolRef `json:"caPoolRef,omitempty"` // Output only. Service Attachment for HTTP, resource is in the format of // `projects/{project}/regions/{region}/serviceAttachments/{service_attachment}`. diff --git a/apis/securesourcemanager/v1alpha1/zz_generated.deepcopy.go b/apis/securesourcemanager/v1alpha1/zz_generated.deepcopy.go index 7a7879de39..f9c0c6d489 100644 --- a/apis/securesourcemanager/v1alpha1/zz_generated.deepcopy.go +++ b/apis/securesourcemanager/v1alpha1/zz_generated.deepcopy.go @@ -67,9 +67,9 @@ func (in *Instance_PrivateConfig) DeepCopyInto(out *Instance_PrivateConfig) { *out = new(bool) **out = **in } - if in.CaPool != nil { - in, out := &in.CaPool, &out.CaPool - *out = new(string) + if in.CaPoolRef != nil { + in, out := &in.CaPoolRef, &out.CaPoolRef + *out = new(v1beta1.PrivateCACAPoolRef) **out = **in } if in.HTTPServiceAttachment != nil { @@ -341,6 +341,11 @@ func (in *SecureSourceManagerInstanceSpec) DeepCopyInto(out *SecureSourceManager *out = new(v1beta1.KMSCryptoKeyRef) **out = **in } + if in.PrivateConfig != nil { + in, out := &in.PrivateConfig, &out.PrivateConfig + *out = new(Instance_PrivateConfig) + (*in).DeepCopyInto(*out) + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SecureSourceManagerInstanceSpec. diff --git a/config/crds/resources/apiextensions.k8s.io_v1_customresourcedefinition_securesourcemanagerinstances.securesourcemanager.cnrm.cloud.google.com.yaml b/config/crds/resources/apiextensions.k8s.io_v1_customresourcedefinition_securesourcemanagerinstances.securesourcemanager.cnrm.cloud.google.com.yaml index 09cb32e2e8..d7504fdd07 100644 --- a/config/crds/resources/apiextensions.k8s.io_v1_customresourcedefinition_securesourcemanagerinstances.securesourcemanager.cnrm.cloud.google.com.yaml +++ b/config/crds/resources/apiextensions.k8s.io_v1_customresourcedefinition_securesourcemanagerinstances.securesourcemanager.cnrm.cloud.google.com.yaml @@ -94,6 +94,51 @@ spec: location: description: Immutable. Location of the instance. type: string + privateConfig: + description: Optional. PrivateConfig includes settings for private + instance. + properties: + caPoolRef: + description: Required. Immutable. CA pool resource, resource must + in the format of `projects/{project}/locations/{location}/caPools/{ca_pool}`. + oneOf: + - not: + required: + - external + required: + - name + - not: + anyOf: + - required: + - name + - required: + - namespace + required: + - external + properties: + external: + description: A reference to an externally managed PrivateCACAPool. + Should be in the format `projects/{project_id}/locations/{region}/caPools/{caPool}`. + type: string + name: + description: The `name` of a `PrivateCACAPool` resource. + type: string + namespace: + description: The `namespace` of a `PrivateCACAPool` resource. + type: string + type: object + httpServiceAttachment: + description: Output only. Service Attachment for HTTP, resource + is in the format of `projects/{project}/regions/{region}/serviceAttachments/{service_attachment}`. + type: string + isPrivate: + description: Required. Immutable. Indicate if it's private instance. + type: boolean + sshServiceAttachment: + description: Output only. Service Attachment for SSH, resource + is in the format of `projects/{project}/regions/{region}/serviceAttachments/{service_attachment}`. + type: string + type: object projectRef: description: Immutable. The Project that this resource belongs to. oneOf: diff --git a/config/tests/samples/create/harness.go b/config/tests/samples/create/harness.go index 3fdddc071d..88c1fa657c 100644 --- a/config/tests/samples/create/harness.go +++ b/config/tests/samples/create/harness.go @@ -855,6 +855,7 @@ func MaybeSkip(t *testing.T, name string, resources []*unstructured.Unstructured case schema.GroupKind{Group: "secretmanager.cnrm.cloud.google.com", Kind: "SecretManagerSecretVersion"}: case schema.GroupKind{Group: "securesourcemanager.cnrm.cloud.google.com", Kind: "SecureSourceManagerInstance"}: + case schema.GroupKind{Group: "securesourcemanager.cnrm.cloud.google.com", Kind: "SecureSourceManagerRepository"}: case schema.GroupKind{Group: "servicedirectory.cnrm.cloud.google.com", Kind: "ServiceDirectoryNamespace"}: case schema.GroupKind{Group: "servicedirectory.cnrm.cloud.google.com", Kind: "ServiceDirectoryService"}: diff --git a/mockgcp/mocksecuresourcemanager/repository.go b/mockgcp/mocksecuresourcemanager/repository.go new file mode 100644 index 0000000000..ee982e9789 --- /dev/null +++ b/mockgcp/mocksecuresourcemanager/repository.go @@ -0,0 +1,167 @@ +// Copyright 2024 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package mocksecuresourcemanager + +import ( + "context" + "fmt" + "strings" + "time" + + longrunning "google.golang.org/genproto/googleapis/longrunning" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" + "google.golang.org/protobuf/proto" + "google.golang.org/protobuf/types/known/emptypb" + "google.golang.org/protobuf/types/known/timestamppb" + + "github.com/GoogleCloudPlatform/k8s-config-connector/mockgcp/common/projects" + pb "github.com/GoogleCloudPlatform/k8s-config-connector/mockgcp/generated/mockgcp/cloud/securesourcemanager/v1" +) + +func (s *secureSourceManagerServer) GetRepository(ctx context.Context, req *pb.GetRepositoryRequest) (*pb.Repository, error) { + name, err := s.parseRepositoryName(req.Name) + if err != nil { + return nil, err + } + + fqn := name.String() + + obj := &pb.Repository{} + if err := s.storage.Get(ctx, fqn, obj); err != nil { + if status.Code(err) == codes.NotFound { + return nil, status.Errorf(codes.NotFound, "Resource '%s' was not found", fqn) + } + return nil, err + } + + return obj, nil +} + +func (s *secureSourceManagerServer) CreateRepository(ctx context.Context, req *pb.CreateRepositoryRequest) (*longrunning.Operation, error) { + reqName := req.Parent + "/repositories/" + req.RepositoryId + name, err := s.parseRepositoryName(reqName) + if err != nil { + return nil, err + } + + fqn := name.String() + + now := time.Now() + + obj := proto.Clone(req.Repository).(*pb.Repository) + obj.Name = fqn + + obj.CreateTime = timestamppb.New(now) + obj.UpdateTime = timestamppb.New(now) + + instanceName, err := s.parseInstanceName(obj.GetInstance()) + if err != nil { + return nil, err + } + + obj.InitialConfig = req.GetRepository().GetInitialConfig() + + prefix := fmt.Sprintf("https://%s-%d", instanceName.InstanceID, name.Project.Number) + domain := "." + name.Location + ".sourcemanager.dev" + obj.Uris = &pb.Repository_URIs{ + Html: prefix + domain + fmt.Sprintf("/%s/%s", name.Project.ID, req.GetRepositoryId()), + Api: prefix + "-api" + domain + fmt.Sprintf("/v1/projects/%s/locations/%s/repositories/%s", name.Project.ID, name.Location, req.GetRepositoryId()), + GitHttps: prefix + "-git" + domain + fmt.Sprintf("/%s/%s.git", name.Project.ID, req.GetRepositoryId()), + } + + if err := s.storage.Create(ctx, fqn, obj); err != nil { + return nil, err + } + + op := &pb.OperationMetadata{ + CreateTime: timestamppb.New(now), + Target: name.String(), + Verb: "create", + ApiVersion: "v1", + } + opPrefix := fmt.Sprintf("projects/%s/locations/%s", name.Project.ID, name.Location) + return s.operations.StartLRO(ctx, opPrefix, op, func() (proto.Message, error) { + op.EndTime = timestamppb.Now() + return obj, nil + }) +} + +func (s *secureSourceManagerServer) DeleteRepository(ctx context.Context, req *pb.DeleteRepositoryRequest) (*longrunning.Operation, error) { + name, err := s.parseRepositoryName(req.GetName()) + if err != nil { + return nil, err + } + + fqn := name.String() + now := time.Now() + + deleted := &pb.Repository{} + if err := s.storage.Delete(ctx, fqn, deleted); err != nil { + return nil, err + } + + op := &pb.OperationMetadata{ + CreateTime: timestamppb.New(now), + Target: name.String(), + Verb: "delete", + ApiVersion: "v1", + } + opPrefix := fmt.Sprintf("projects/%s/locations/%s", name.Project.ID, name.Location) + return s.operations.StartLRO(ctx, opPrefix, op, func() (proto.Message, error) { + op.EndTime = timestamppb.Now() + return &emptypb.Empty{}, nil + }) +} + +type RepositoryName struct { + Project *projects.ProjectData + Location string + RepositoryID string +} + +func (n *RepositoryName) String() string { + return fmt.Sprintf("projects/%s/locations/%s/repositories/%s", n.Project.ID, n.Location, n.RepositoryID) +} + +// func (n *RepositoryName) Target() string { +// return fmt.Sprintf("projects/%s/locations/%s/repositories/%s", n.Project.ID, n.Location, n.RepositoryID) +// } + +// parseRepositoryName parses a string into a RepositoryName. +// The expected form is projects/*/locations/*/repositories/* +func (s *MockService) parseRepositoryName(name string) (*RepositoryName, error) { + tokens := strings.Split(name, "/") + + if len(tokens) == 6 && tokens[0] == "projects" && tokens[2] == "locations" && tokens[4] == "repositories" { + projectName, err := projects.ParseProjectName(tokens[0] + "/" + tokens[1]) + if err != nil { + return nil, err + } + project, err := s.Projects.GetProject(projectName) + if err != nil { + return nil, err + } + + name := &RepositoryName{ + Project: project, + Location: tokens[3], + RepositoryID: tokens[5], + } + return name, nil + } else { + return nil, status.Errorf(codes.InvalidArgument, "name %q is not valid", name) + } +} diff --git a/pkg/clients/generated/apis/securesourcemanager/v1alpha1/securesourcemanagerinstance_types.go b/pkg/clients/generated/apis/securesourcemanager/v1alpha1/securesourcemanagerinstance_types.go index ec78c7755a..b001f58475 100644 --- a/pkg/clients/generated/apis/securesourcemanager/v1alpha1/securesourcemanagerinstance_types.go +++ b/pkg/clients/generated/apis/securesourcemanager/v1alpha1/securesourcemanagerinstance_types.go @@ -35,6 +35,24 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) +type InstancePrivateConfig struct { + /* Required. Immutable. CA pool resource, resource must in the format of `projects/{project}/locations/{location}/caPools/{ca_pool}`. */ + // +optional + CaPoolRef *v1alpha1.ResourceRef `json:"caPoolRef,omitempty"` + + /* Output only. Service Attachment for HTTP, resource is in the format of `projects/{project}/regions/{region}/serviceAttachments/{service_attachment}`. */ + // +optional + HttpServiceAttachment *string `json:"httpServiceAttachment,omitempty"` + + /* Required. Immutable. Indicate if it's private instance. */ + // +optional + IsPrivate *bool `json:"isPrivate,omitempty"` + + /* Output only. Service Attachment for SSH, resource is in the format of `projects/{project}/regions/{region}/serviceAttachments/{service_attachment}`. */ + // +optional + SshServiceAttachment *string `json:"sshServiceAttachment,omitempty"` +} + type SecureSourceManagerInstanceSpec struct { /* Optional. Immutable. Customer-managed encryption key name. */ // +optional @@ -43,6 +61,10 @@ type SecureSourceManagerInstanceSpec struct { /* Immutable. Location of the instance. */ Location string `json:"location"` + /* Optional. PrivateConfig includes settings for private instance. */ + // +optional + PrivateConfig *InstancePrivateConfig `json:"privateConfig,omitempty"` + /* Immutable. The Project that this resource belongs to. */ ProjectRef v1alpha1.ResourceRef `json:"projectRef"` diff --git a/pkg/clients/generated/apis/securesourcemanager/v1alpha1/zz_generated.deepcopy.go b/pkg/clients/generated/apis/securesourcemanager/v1alpha1/zz_generated.deepcopy.go index 4d4669c83f..0e0fd26601 100644 --- a/pkg/clients/generated/apis/securesourcemanager/v1alpha1/zz_generated.deepcopy.go +++ b/pkg/clients/generated/apis/securesourcemanager/v1alpha1/zz_generated.deepcopy.go @@ -96,6 +96,42 @@ func (in *InstanceObservedStateStatus) DeepCopy() *InstanceObservedStateStatus { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *InstancePrivateConfig) DeepCopyInto(out *InstancePrivateConfig) { + *out = *in + if in.CaPoolRef != nil { + in, out := &in.CaPoolRef, &out.CaPoolRef + *out = new(k8sv1alpha1.ResourceRef) + **out = **in + } + if in.HttpServiceAttachment != nil { + in, out := &in.HttpServiceAttachment, &out.HttpServiceAttachment + *out = new(string) + **out = **in + } + if in.IsPrivate != nil { + in, out := &in.IsPrivate, &out.IsPrivate + *out = new(bool) + **out = **in + } + if in.SshServiceAttachment != nil { + in, out := &in.SshServiceAttachment, &out.SshServiceAttachment + *out = new(string) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new InstancePrivateConfig. +func (in *InstancePrivateConfig) DeepCopy() *InstancePrivateConfig { + if in == nil { + return nil + } + out := new(InstancePrivateConfig) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *RepositoryInitialConfig) DeepCopyInto(out *RepositoryInitialConfig) { *out = *in @@ -263,6 +299,11 @@ func (in *SecureSourceManagerInstanceSpec) DeepCopyInto(out *SecureSourceManager *out = new(k8sv1alpha1.ResourceRef) **out = **in } + if in.PrivateConfig != nil { + in, out := &in.PrivateConfig, &out.PrivateConfig + *out = new(InstancePrivateConfig) + (*in).DeepCopyInto(*out) + } out.ProjectRef = in.ProjectRef if in.ResourceID != nil { in, out := &in.ResourceID, &out.ResourceID diff --git a/pkg/controller/direct/registry/registry.go b/pkg/controller/direct/registry/registry.go index a2cf44272e..20527466bd 100644 --- a/pkg/controller/direct/registry/registry.go +++ b/pkg/controller/direct/registry/registry.go @@ -143,6 +143,8 @@ func SupportsIAM(groupKind schema.GroupKind) (bool, error) { return false, nil case schema.GroupKind{Group: "securesourcemanager.cnrm.cloud.google.com", Kind: "SecureSourceManagerInstance"}: return false, nil + case schema.GroupKind{Group: "securesourcemanager.cnrm.cloud.google.com", Kind: "SecureSourceManagerRepository"}: + return false, nil case schema.GroupKind{Group: "discoveryengine.cnrm.cloud.google.com", Kind: "DiscoveryEngineDataStore"}: return false, nil } diff --git a/pkg/controller/direct/securesourcemanager/mapper.generated.go b/pkg/controller/direct/securesourcemanager/mapper.generated.go index 12e6552143..a35c75f866 100644 --- a/pkg/controller/direct/securesourcemanager/mapper.generated.go +++ b/pkg/controller/direct/securesourcemanager/mapper.generated.go @@ -49,10 +49,11 @@ func Instance_PrivateConfig_FromProto(mapCtx *direct.MapContext, in *pb.Instance } out := &krm.Instance_PrivateConfig{} out.IsPrivate = direct.LazyPtr(in.GetIsPrivate()) - out.CaPool = direct.LazyPtr(in.GetCaPool()) + if in.GetCaPool() != "" { + out.CaPoolRef = &refs.PrivateCACAPoolRef{External: in.GetCaPool()} + } out.HTTPServiceAttachment = direct.LazyPtr(in.GetHttpServiceAttachment()) out.SSHServiceAttachment = direct.LazyPtr(in.GetSshServiceAttachment()) - // MISSING: PscAllowedProjects return out } func Instance_PrivateConfig_ToProto(mapCtx *direct.MapContext, in *krm.Instance_PrivateConfig) *pb.Instance_PrivateConfig { @@ -61,10 +62,11 @@ func Instance_PrivateConfig_ToProto(mapCtx *direct.MapContext, in *krm.Instance_ } out := &pb.Instance_PrivateConfig{} out.IsPrivate = direct.ValueOf(in.IsPrivate) - out.CaPool = direct.ValueOf(in.CaPool) + if in.CaPoolRef != nil { + out.CaPool = in.CaPoolRef.External + } out.HttpServiceAttachment = direct.ValueOf(in.HTTPServiceAttachment) out.SshServiceAttachment = direct.ValueOf(in.SSHServiceAttachment) - // MISSING: PscAllowedProjects return out } func Repository_InitialConfig_FromProto(mapCtx *direct.MapContext, in *pb.Repository_InitialConfig) *krm.Repository_InitialConfig { @@ -118,7 +120,6 @@ func SecureSourceManagerInstanceObservedState_FromProto(mapCtx *direct.MapContex // MISSING: CreateTime // MISSING: UpdateTime // MISSING: Labels - // MISSING: PrivateConfig out.State = direct.Enum_FromProto(mapCtx, in.GetState()) out.StateNote = direct.Enum_FromProto(mapCtx, in.GetStateNote()) out.HostConfig = Instance_HostConfig_FromProto(mapCtx, in.GetHostConfig()) @@ -133,7 +134,6 @@ func SecureSourceManagerInstanceObservedState_ToProto(mapCtx *direct.MapContext, // MISSING: CreateTime // MISSING: UpdateTime // MISSING: Labels - // MISSING: PrivateConfig out.State = direct.Enum_ToProto[pb.Instance_State](mapCtx, in.State) out.StateNote = direct.Enum_ToProto[pb.Instance_StateNote](mapCtx, in.StateNote) out.HostConfig = Instance_HostConfig_ToProto(mapCtx, in.HostConfig) @@ -148,7 +148,7 @@ func SecureSourceManagerInstanceSpec_FromProto(mapCtx *direct.MapContext, in *pb // MISSING: CreateTime // MISSING: UpdateTime // MISSING: Labels - // MISSING: PrivateConfig + out.PrivateConfig = Instance_PrivateConfig_FromProto(mapCtx, in.GetPrivateConfig()) if in.GetKmsKey() != "" { out.KmsKeyRef = &refs.KMSCryptoKeyRef{External: in.GetKmsKey()} } @@ -163,7 +163,7 @@ func SecureSourceManagerInstanceSpec_ToProto(mapCtx *direct.MapContext, in *krm. // MISSING: CreateTime // MISSING: UpdateTime // MISSING: Labels - // MISSING: PrivateConfig + out.PrivateConfig = Instance_PrivateConfig_ToProto(mapCtx, in.PrivateConfig) if in.KmsKeyRef != nil { out.KmsKey = in.KmsKeyRef.External } @@ -177,7 +177,7 @@ func SecureSourceManagerRepositorySpec_FromProto(mapCtx *direct.MapContext, in * // MISSING: Name // MISSING: Description if in.GetInstance() != "" { - out.InstanceRef = &krm.SecureSourceManagerInstanceRef{External: in.GetInstance()} + out.InstanceRef = SecureSourceManagerRepositorySpec_InstanceRef_FromProto(mapCtx, in.GetInstance()) } // MISSING: Uid // MISSING: CreateTime diff --git a/pkg/controller/direct/securesourcemanager/repository_controller.go b/pkg/controller/direct/securesourcemanager/repository_controller.go new file mode 100644 index 0000000000..a74b7bc177 --- /dev/null +++ b/pkg/controller/direct/securesourcemanager/repository_controller.go @@ -0,0 +1,226 @@ +// Copyright 2024 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package securesourcemanager + +import ( + "context" + "fmt" + "strings" + + refs "github.com/GoogleCloudPlatform/k8s-config-connector/apis/refs/v1beta1" + krm "github.com/GoogleCloudPlatform/k8s-config-connector/apis/securesourcemanager/v1alpha1" + "github.com/GoogleCloudPlatform/k8s-config-connector/pkg/config" + "github.com/GoogleCloudPlatform/k8s-config-connector/pkg/controller/direct" + "github.com/GoogleCloudPlatform/k8s-config-connector/pkg/controller/direct/directbase" + "github.com/GoogleCloudPlatform/k8s-config-connector/pkg/controller/direct/registry" + + gcp "cloud.google.com/go/securesourcemanager/apiv1" + + securesourcemanagerpb "cloud.google.com/go/securesourcemanager/apiv1/securesourcemanagerpb" + "google.golang.org/api/option" + + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/klog/v2" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +func init() { + registry.RegisterModel(krm.SecureSourceManagerRepositoryGVK, NewSecureSourceManagerRepositoryModel) +} + +func NewSecureSourceManagerRepositoryModel(ctx context.Context, config *config.ControllerConfig) (directbase.Model, error) { + return &modelSecureSourceManagerRepository{config: *config}, nil +} + +var _ directbase.Model = &modelSecureSourceManagerRepository{} + +type modelSecureSourceManagerRepository struct { + config config.ControllerConfig +} + +func (m *modelSecureSourceManagerRepository) client(ctx context.Context) (*gcp.Client, error) { + var opts []option.ClientOption + opts, err := m.config.RESTClientOptions() + if err != nil { + return nil, err + } + gcpClient, err := gcp.NewRESTClient(ctx, opts...) + if err != nil { + return nil, fmt.Errorf("building Repository client: %w", err) + } + return gcpClient, err +} + +func (m *modelSecureSourceManagerRepository) AdapterForObject(ctx context.Context, reader client.Reader, u *unstructured.Unstructured) (directbase.Adapter, error) { + obj := &krm.SecureSourceManagerRepository{} + if err := runtime.DefaultUnstructuredConverter.FromUnstructured(u.Object, &obj); err != nil { + return nil, fmt.Errorf("error converting to %T: %w", obj, err) + } + + // Resolve SecureSourceManagerInstanceRef + instanceRef := obj.Spec.InstanceRef + normalizedExternal, err := instanceRef.NormalizedExternal(ctx, reader, obj.Namespace) + if err != nil { + return nil, err + } + obj.Spec.InstanceRef.External = normalizedExternal + + id, err := krm.NewSecureSourceManagerRepositoryRef(ctx, reader, obj) + if err != nil { + return nil, err + } + + // Get securesourcemanager GCP client + gcpClient, err := m.client(ctx) + if err != nil { + return nil, err + } + return &SecureSourceManagerRepositoryAdapter{ + id: id, + gcpClient: gcpClient, + desired: obj, + }, nil +} + +func (m *modelSecureSourceManagerRepository) AdapterForURL(ctx context.Context, url string) (directbase.Adapter, error) { + // TODO: Support URLs + return nil, nil +} + +type SecureSourceManagerRepositoryAdapter struct { + id *krm.SecureSourceManagerRepositoryRef + gcpClient *gcp.Client + desired *krm.SecureSourceManagerRepository + actual *securesourcemanagerpb.Repository +} + +var _ directbase.Adapter = &SecureSourceManagerRepositoryAdapter{} + +func (a *SecureSourceManagerRepositoryAdapter) Find(ctx context.Context) (bool, error) { + log := klog.FromContext(ctx) + log.V(2).Info("getting SecureSourceManagerRepository", "name", a.id.External) + + req := &securesourcemanagerpb.GetRepositoryRequest{Name: a.id.External} + repositorypb, err := a.gcpClient.GetRepository(ctx, req) + if err != nil { + if direct.IsNotFound(err) { + return false, nil + } + return false, fmt.Errorf("getting SecureSourceManagerRepository %q: %w", a.id.External, err) + } + + a.actual = repositorypb + return true, nil +} + +func (a *SecureSourceManagerRepositoryAdapter) Create(ctx context.Context, createOp *directbase.CreateOperation) error { + log := klog.FromContext(ctx) + log.V(2).Info("creating Repository", "name", a.id.External) + mapCtx := &direct.MapContext{} + + desired := a.desired.DeepCopy() + resource := SecureSourceManagerRepositorySpec_ToProto(mapCtx, &desired.Spec) + if mapCtx.Err() != nil { + return mapCtx.Err() + } + + parent, err := a.id.Parent() + if err != nil { + return err + } + repositoryID, err := a.id.ResourceID() + if err != nil { + return err + } + + req := &securesourcemanagerpb.CreateRepositoryRequest{ + Parent: parent.String(), + Repository: resource, + RepositoryId: repositoryID, + } + op, err := a.gcpClient.CreateRepository(ctx, req) + if err != nil { + return fmt.Errorf("creating Repository %s: %w", a.id.External, err) + } + created, err := op.Wait(ctx) + if err != nil { + return fmt.Errorf("Repository %s waiting creation: %w", a.id.External, err) + } + log.V(2).Info("successfully created Repository", "name", a.id.External) + + status := &krm.SecureSourceManagerRepositoryStatus{} + status.ObservedState = SecureSourceManagerRepositoryObservedState_FromProto(mapCtx, created) + if mapCtx.Err() != nil { + return mapCtx.Err() + } + status.ExternalRef = &a.id.External + return createOp.UpdateStatus(ctx, status, nil) +} + +func (a *SecureSourceManagerRepositoryAdapter) Update(ctx context.Context, updateOp *directbase.UpdateOperation) error { + log := klog.FromContext(ctx) + log.Info("update of SecureSourceManagerRepository not supported") + return nil +} + +func (a *SecureSourceManagerRepositoryAdapter) Export(ctx context.Context) (*unstructured.Unstructured, error) { + if a.actual == nil { + return nil, fmt.Errorf("Find() not called") + } + u := &unstructured.Unstructured{} + + obj := &krm.SecureSourceManagerRepository{} + mapCtx := &direct.MapContext{} + obj.Spec = direct.ValueOf(SecureSourceManagerRepositorySpec_FromProto(mapCtx, a.actual)) + if mapCtx.Err() != nil { + return nil, mapCtx.Err() + } + parent, err := a.id.Parent() + if err != nil { + return nil, err + } + repositoryID, err := a.id.ResourceID() + if err != nil { + return nil, err + } + obj.Spec.ProjectRef = &refs.ProjectRef{Name: parent.ProjectID} + obj.Spec.Location = parent.Location + uObj, err := runtime.DefaultUnstructuredConverter.ToUnstructured(obj) + if err != nil { + return nil, err + } + u.SetName(repositoryID) + u.SetGroupVersionKind(krm.SecureSourceManagerRepositoryGVK) + u.Object = uObj + return u, nil +} + +// Delete implements the Adapter interface. +func (a *SecureSourceManagerRepositoryAdapter) Delete(ctx context.Context, deleteOp *directbase.DeleteOperation) (bool, error) { + log := klog.FromContext(ctx) + log.V(2).Info("deleting Repository", "name", a.id.External) + + req := &securesourcemanagerpb.DeleteRepositoryRequest{Name: a.id.External} + _, err := a.gcpClient.DeleteRepository(ctx, req) + // TODO - remove after the Go protobuf fix is in. https://github.com/golang/protobuf/issues/1620#issuecomment-2402608919 + // Handles the LRO parsing error. + if err != nil { + if !strings.Contains(err.Error(), "(line 14:3): missing \"value\" field") { + return false, fmt.Errorf("deleting Repository %s: %w", a.id.External, err) + } + } + return true, nil +} diff --git a/pkg/test/resourcefixture/testdata/basic/securesourcemanager/securesourcemanagerrepository/securesourcemanagerrepositorybasic/_generated_object_securesourcemanagerrepositorybasic.golden.yaml b/pkg/test/resourcefixture/testdata/basic/securesourcemanager/securesourcemanagerrepository/securesourcemanagerrepositorybasic/_generated_object_securesourcemanagerrepositorybasic.golden.yaml new file mode 100644 index 0000000000..e03bfef5d6 --- /dev/null +++ b/pkg/test/resourcefixture/testdata/basic/securesourcemanager/securesourcemanagerrepository/securesourcemanagerrepositorybasic/_generated_object_securesourcemanagerrepositorybasic.golden.yaml @@ -0,0 +1,31 @@ +apiVersion: securesourcemanager.cnrm.cloud.google.com/v1alpha1 +kind: SecureSourceManagerRepository +metadata: + finalizers: + - cnrm.cloud.google.com/finalizer + - cnrm.cloud.google.com/deletion-defender + generation: 1 + labels: + cnrm-test: "true" + name: ssmrepository-${uniqueId} + namespace: ${uniqueId} +spec: + instanceRef: + name: ssminstance-dep-${uniqueId} + location: us-central1 + projectRef: + external: ${projectId} +status: + conditions: + - lastTransitionTime: "1970-01-01T00:00:00Z" + message: The resource is up to date + reason: UpToDate + status: "True" + type: Ready + externalRef: projects/${projectId}/locations/us-central1/repositories/ssmrepository-${uniqueId} + observedGeneration: 1 + observedState: + uris: + api: https://ssminstance-dep-${uniqueId}-${projectNumber}-api.us-central1.sourcemanager.dev/v1/projects/${projectId}/locations/us-central1/repositories/ssmrepository-${uniqueId} + gitHTTPS: https://ssminstance-dep-${uniqueId}-${projectNumber}-git.us-central1.sourcemanager.dev/${projectId}/ssmrepository-${uniqueId}.git + html: https://ssminstance-dep-${uniqueId}-${projectNumber}.us-central1.sourcemanager.dev/${projectId}/ssmrepository-${uniqueId} diff --git a/pkg/test/resourcefixture/testdata/basic/securesourcemanager/securesourcemanagerrepository/securesourcemanagerrepositorybasic/_http.log b/pkg/test/resourcefixture/testdata/basic/securesourcemanager/securesourcemanagerrepository/securesourcemanagerrepositorybasic/_http.log new file mode 100644 index 0000000000..ab9f31955d --- /dev/null +++ b/pkg/test/resourcefixture/testdata/basic/securesourcemanager/securesourcemanagerrepository/securesourcemanagerrepositorybasic/_http.log @@ -0,0 +1,353 @@ +GET https://securesourcemanager.googleapis.com/v1/projects/${projectId}/locations/us-central1/instances/ssminstance-dep-${uniqueId}?%24alt=json%3Benum-encoding%3Dint +Content-Type: application/json +User-Agent: kcc/controller-manager +x-goog-request-params: name=projects%2F${projectId}%2Flocations%2Fus-central1%2Finstances%2Fssminstance-dep-${uniqueId} + +404 Not Found +Cache-Control: private +Content-Type: application/json; charset=UTF-8 +Server: ESF +Vary: Origin +Vary: X-Origin +Vary: Referer +X-Content-Type-Options: nosniff +X-Frame-Options: SAMEORIGIN +X-Xss-Protection: 0 + +{ + "error": { + "code": 404, + "message": "Resource 'projects/${projectId}/locations/us-central1/instances/ssminstance-dep-${uniqueId}' was not found", + "status": "NOT_FOUND" + } +} + +--- + +POST https://securesourcemanager.googleapis.com/v1/projects/${projectId}/locations/us-central1/instances?%24alt=json%3Benum-encoding%3Dint&instanceId=ssminstance-dep-${uniqueId} +Content-Type: application/json +User-Agent: kcc/controller-manager +x-goog-request-params: parent=projects%2F${projectId}%2Flocations%2Fus-central1 + +{} + +200 OK +Cache-Control: private +Content-Type: application/json; charset=UTF-8 +Server: ESF +Vary: Origin +Vary: X-Origin +Vary: Referer +X-Content-Type-Options: nosniff +X-Frame-Options: SAMEORIGIN +X-Xss-Protection: 0 + +{ + "metadata": { + "@type": "type.googleapis.com/google.cloud.securesourcemanager.v1.OperationMetadata", + "apiVersion": "v1", + "createTime": "2024-04-01T12:34:56.123456Z", + "target": "projects/${projectId}/locations/us-central1/instances/ssminstance-dep-${uniqueId}", + "verb": "create" + }, + "name": "projects/${projectId}/locations/us-central1/operations/${operationID}" +} + +--- + +GET https://securesourcemanager.googleapis.com/v1/projects/${projectId}/locations/us-central1/operations/${operationID} +Content-Type: application/json +User-Agent: kcc/controller-manager +x-goog-request-params: name=projects%2F${projectId}%2Flocations%2Fus-central1%2Foperations%2F${operationID} + +200 OK +Cache-Control: private +Content-Type: application/json; charset=UTF-8 +Server: ESF +Vary: Origin +Vary: X-Origin +Vary: Referer +X-Content-Type-Options: nosniff +X-Frame-Options: SAMEORIGIN +X-Xss-Protection: 0 + +{ + "done": true, + "metadata": { + "@type": "type.googleapis.com/google.cloud.securesourcemanager.v1.OperationMetadata", + "apiVersion": "v1", + "createTime": "2024-04-01T12:34:56.123456Z", + "endTime": "2024-04-01T12:34:56.123456Z", + "target": "projects/${projectId}/locations/us-central1/instances/ssminstance-dep-${uniqueId}", + "verb": "create" + }, + "name": "projects/${projectId}/locations/us-central1/operations/${operationID}", + "response": { + "@type": "type.googleapis.com/google.cloud.securesourcemanager.v1.Instance", + "createTime": "2024-04-01T12:34:56.123456Z", + "hostConfig": { + "api": "ssminstance-dep-${uniqueId}-${projectNumber}-api.us-central1.sourcemanager.dev", + "gitHttp": "ssminstance-dep-${uniqueId}-${projectNumber}-git.us-central1.sourcemanager.dev", + "gitSsh": "ssminstance-dep-${uniqueId}-${projectNumber}-ssh.us-central1.sourcemanager.dev", + "html": "ssminstance-dep-${uniqueId}-${projectNumber}.us-central1.sourcemanager.dev" + }, + "name": "projects/${projectId}/locations/us-central1/instances/ssminstance-dep-${uniqueId}", + "state": "ACTIVE", + "updateTime": "2024-04-01T12:34:56.123456Z" + } +} + +--- + +GET https://securesourcemanager.googleapis.com/v1/projects/${projectId}/locations/us-central1/repositories/ssmrepository-${uniqueId}?%24alt=json%3Benum-encoding%3Dint +Content-Type: application/json +User-Agent: kcc/controller-manager +x-goog-request-params: name=projects%2F${projectId}%2Flocations%2Fus-central1%2Frepositories%2Fssmrepository-${uniqueId} + +404 Not Found +Cache-Control: private +Content-Type: application/json; charset=UTF-8 +Server: ESF +Vary: Origin +Vary: X-Origin +Vary: Referer +X-Content-Type-Options: nosniff +X-Frame-Options: SAMEORIGIN +X-Xss-Protection: 0 + +{ + "error": { + "code": 404, + "message": "Resource 'projects/${projectId}/locations/us-central1/repositories/ssmrepository-${uniqueId}' was not found", + "status": "NOT_FOUND" + } +} + +--- + +POST https://securesourcemanager.googleapis.com/v1/projects/${projectId}/locations/us-central1/repositories?%24alt=json%3Benum-encoding%3Dint&repositoryId=ssmrepository-${uniqueId} +Content-Type: application/json +User-Agent: kcc/controller-manager +x-goog-request-params: parent=projects%2F${projectId}%2Flocations%2Fus-central1 + +{ + "instance": "projects/${projectId}/locations/us-central1/instances/ssminstance-dep-${uniqueId}" +} + +200 OK +Cache-Control: private +Content-Type: application/json; charset=UTF-8 +Server: ESF +Vary: Origin +Vary: X-Origin +Vary: Referer +X-Content-Type-Options: nosniff +X-Frame-Options: SAMEORIGIN +X-Xss-Protection: 0 + +{ + "metadata": { + "@type": "type.googleapis.com/google.cloud.securesourcemanager.v1.OperationMetadata", + "apiVersion": "v1", + "createTime": "2024-04-01T12:34:56.123456Z", + "target": "projects/${projectId}/locations/us-central1/repositories/ssmrepository-${uniqueId}", + "verb": "create" + }, + "name": "projects/${projectId}/locations/us-central1/operations/${operationID}" +} + +--- + +GET https://securesourcemanager.googleapis.com/v1/projects/${projectId}/locations/us-central1/operations/${operationID} +Content-Type: application/json +User-Agent: kcc/controller-manager +x-goog-request-params: name=projects%2F${projectId}%2Flocations%2Fus-central1%2Foperations%2F${operationID} + +200 OK +Cache-Control: private +Content-Type: application/json; charset=UTF-8 +Server: ESF +Vary: Origin +Vary: X-Origin +Vary: Referer +X-Content-Type-Options: nosniff +X-Frame-Options: SAMEORIGIN +X-Xss-Protection: 0 + +{ + "done": true, + "metadata": { + "@type": "type.googleapis.com/google.cloud.securesourcemanager.v1.OperationMetadata", + "apiVersion": "v1", + "createTime": "2024-04-01T12:34:56.123456Z", + "endTime": "2024-04-01T12:34:56.123456Z", + "target": "projects/${projectId}/locations/us-central1/repositories/ssmrepository-${uniqueId}", + "verb": "create" + }, + "name": "projects/${projectId}/locations/us-central1/operations/${operationID}", + "response": { + "@type": "type.googleapis.com/google.cloud.securesourcemanager.v1.Repository", + "createTime": "2024-04-01T12:34:56.123456Z", + "instance": "projects/${projectId}/locations/us-central1/instances/ssminstance-dep-${uniqueId}", + "name": "projects/${projectId}/locations/us-central1/repositories/ssmrepository-${uniqueId}", + "updateTime": "2024-04-01T12:34:56.123456Z", + "uris": { + "api": "https://ssminstance-dep-${uniqueId}-${projectNumber}-api.us-central1.sourcemanager.dev/v1/projects/${projectId}/locations/us-central1/repositories/ssmrepository-${uniqueId}", + "gitHttps": "https://ssminstance-dep-${uniqueId}-${projectNumber}-git.us-central1.sourcemanager.dev/${projectId}/ssmrepository-${uniqueId}.git", + "html": "https://ssminstance-dep-${uniqueId}-${projectNumber}.us-central1.sourcemanager.dev/${projectId}/ssmrepository-${uniqueId}" + } + } +} + +--- + +GET https://securesourcemanager.googleapis.com/v1/projects/${projectId}/locations/us-central1/repositories/ssmrepository-${uniqueId}?%24alt=json%3Benum-encoding%3Dint +Content-Type: application/json +User-Agent: kcc/controller-manager +x-goog-request-params: name=projects%2F${projectId}%2Flocations%2Fus-central1%2Frepositories%2Fssmrepository-${uniqueId} + +200 OK +Cache-Control: private +Content-Type: application/json; charset=UTF-8 +Server: ESF +Vary: Origin +Vary: X-Origin +Vary: Referer +X-Content-Type-Options: nosniff +X-Frame-Options: SAMEORIGIN +X-Xss-Protection: 0 + +{ + "createTime": "2024-04-01T12:34:56.123456Z", + "instance": "projects/${projectId}/locations/us-central1/instances/ssminstance-dep-${uniqueId}", + "name": "projects/${projectId}/locations/us-central1/repositories/ssmrepository-${uniqueId}", + "updateTime": "2024-04-01T12:34:56.123456Z", + "uris": { + "api": "https://ssminstance-dep-${uniqueId}-${projectNumber}-api.us-central1.sourcemanager.dev/v1/projects/${projectId}/locations/us-central1/repositories/ssmrepository-${uniqueId}", + "gitHttps": "https://ssminstance-dep-${uniqueId}-${projectNumber}-git.us-central1.sourcemanager.dev/${projectId}/ssmrepository-${uniqueId}.git", + "html": "https://ssminstance-dep-${uniqueId}-${projectNumber}.us-central1.sourcemanager.dev/${projectId}/ssmrepository-${uniqueId}" + } +} + +--- + +DELETE https://securesourcemanager.googleapis.com/v1/projects/${projectId}/locations/us-central1/repositories/ssmrepository-${uniqueId}?%24alt=json%3Benum-encoding%3Dint +Content-Type: application/json +User-Agent: kcc/controller-manager +x-goog-request-params: name=projects%2F${projectId}%2Flocations%2Fus-central1%2Frepositories%2Fssmrepository-${uniqueId} + +200 OK +Cache-Control: private +Content-Type: application/json; charset=UTF-8 +Server: ESF +Vary: Origin +Vary: X-Origin +Vary: Referer +X-Content-Type-Options: nosniff +X-Frame-Options: SAMEORIGIN +X-Xss-Protection: 0 + +{ + "metadata": { + "@type": "type.googleapis.com/google.cloud.securesourcemanager.v1.OperationMetadata", + "apiVersion": "v1", + "createTime": "2024-04-01T12:34:56.123456Z", + "target": "projects/${projectId}/locations/us-central1/repositories/ssmrepository-${uniqueId}", + "verb": "delete" + }, + "name": "projects/${projectId}/locations/us-central1/operations/${operationID}" +} + +--- + +GET https://securesourcemanager.googleapis.com/v1/projects/${projectId}/locations/us-central1/instances/ssminstance-dep-${uniqueId}?%24alt=json%3Benum-encoding%3Dint +Content-Type: application/json +User-Agent: kcc/controller-manager +x-goog-request-params: name=projects%2F${projectId}%2Flocations%2Fus-central1%2Finstances%2Fssminstance-dep-${uniqueId} + +200 OK +Cache-Control: private +Content-Type: application/json; charset=UTF-8 +Server: ESF +Vary: Origin +Vary: X-Origin +Vary: Referer +X-Content-Type-Options: nosniff +X-Frame-Options: SAMEORIGIN +X-Xss-Protection: 0 + +{ + "createTime": "2024-04-01T12:34:56.123456Z", + "hostConfig": { + "api": "ssminstance-dep-${uniqueId}-${projectNumber}-api.us-central1.sourcemanager.dev", + "gitHttp": "ssminstance-dep-${uniqueId}-${projectNumber}-git.us-central1.sourcemanager.dev", + "gitSsh": "ssminstance-dep-${uniqueId}-${projectNumber}-ssh.us-central1.sourcemanager.dev", + "html": "ssminstance-dep-${uniqueId}-${projectNumber}.us-central1.sourcemanager.dev" + }, + "name": "projects/${projectId}/locations/us-central1/instances/ssminstance-dep-${uniqueId}", + "state": 2, + "updateTime": "2024-04-01T12:34:56.123456Z" +} + +--- + +DELETE https://securesourcemanager.googleapis.com/v1/projects/${projectId}/locations/us-central1/instances/ssminstance-dep-${uniqueId}?%24alt=json%3Benum-encoding%3Dint +Content-Type: application/json +User-Agent: kcc/controller-manager +x-goog-request-params: name=projects%2F${projectId}%2Flocations%2Fus-central1%2Finstances%2Fssminstance-dep-${uniqueId} + +200 OK +Cache-Control: private +Content-Type: application/json; charset=UTF-8 +Server: ESF +Vary: Origin +Vary: X-Origin +Vary: Referer +X-Content-Type-Options: nosniff +X-Frame-Options: SAMEORIGIN +X-Xss-Protection: 0 + +{ + "metadata": { + "@type": "type.googleapis.com/google.cloud.securesourcemanager.v1.OperationMetadata", + "apiVersion": "v1", + "createTime": "2024-04-01T12:34:56.123456Z", + "target": "projects/${projectId}/locations/us-central1/instances/ssminstance-dep-${uniqueId}", + "verb": "delete" + }, + "name": "projects/${projectId}/locations/us-central1/operations/${operationID}" +} + +--- + +GET https://securesourcemanager.googleapis.com/v1/projects/${projectId}/locations/us-central1/operations/${operationID} +Content-Type: application/json +User-Agent: kcc/controller-manager +x-goog-request-params: name=projects%2F${projectId}%2Flocations%2Fus-central1%2Foperations%2F${operationID} + +200 OK +Cache-Control: private +Content-Type: application/json; charset=UTF-8 +Server: ESF +Vary: Origin +Vary: X-Origin +Vary: Referer +X-Content-Type-Options: nosniff +X-Frame-Options: SAMEORIGIN +X-Xss-Protection: 0 + +{ + "done": true, + "metadata": { + "@type": "type.googleapis.com/google.cloud.securesourcemanager.v1.OperationMetadata", + "apiVersion": "v1", + "createTime": "2024-04-01T12:34:56.123456Z", + "endTime": "2024-04-01T12:34:56.123456Z", + "target": "projects/${projectId}/locations/us-central1/instances/ssminstance-dep-${uniqueId}", + "verb": "delete" + }, + "name": "projects/${projectId}/locations/us-central1/operations/${operationID}", + "response": { + "@type": "type.googleapis.com/google.protobuf.Empty" + } +} \ No newline at end of file diff --git a/pkg/test/resourcefixture/testdata/basic/securesourcemanager/securesourcemanagerrepository/securesourcemanagerrepositorybasic/create.yaml b/pkg/test/resourcefixture/testdata/basic/securesourcemanager/securesourcemanagerrepository/securesourcemanagerrepositorybasic/create.yaml new file mode 100644 index 0000000000..eacf771676 --- /dev/null +++ b/pkg/test/resourcefixture/testdata/basic/securesourcemanager/securesourcemanagerrepository/securesourcemanagerrepositorybasic/create.yaml @@ -0,0 +1,24 @@ +# Copyright 2024 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +apiVersion: securesourcemanager.cnrm.cloud.google.com/v1alpha1 +kind: SecureSourceManagerRepository +metadata: + name: ssmrepository-${uniqueId} +spec: + location: us-central1 + projectRef: + external: ${projectId} + instanceRef: + name: ssminstance-dep-${uniqueId} \ No newline at end of file diff --git a/pkg/test/resourcefixture/testdata/basic/securesourcemanager/securesourcemanagerrepository/securesourcemanagerrepositorybasic/dependencies.yaml b/pkg/test/resourcefixture/testdata/basic/securesourcemanager/securesourcemanagerrepository/securesourcemanagerrepositorybasic/dependencies.yaml new file mode 100644 index 0000000000..4ccd139a65 --- /dev/null +++ b/pkg/test/resourcefixture/testdata/basic/securesourcemanager/securesourcemanagerrepository/securesourcemanagerrepositorybasic/dependencies.yaml @@ -0,0 +1,22 @@ +# Copyright 2024 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +apiVersion: securesourcemanager.cnrm.cloud.google.com/v1alpha1 +kind: SecureSourceManagerInstance +metadata: + name: ssminstance-dep-${uniqueId} +spec: + location: us-central1 + projectRef: + external: ${projectId} diff --git a/pkg/test/resourcefixture/testdata/basic/securesourcemanager/securesourcemanagerrepository/securesourcemanagerrepositoryfull/_generated_object_securesourcemanagerrepositoryfull.golden.yaml b/pkg/test/resourcefixture/testdata/basic/securesourcemanager/securesourcemanagerrepository/securesourcemanagerrepositoryfull/_generated_object_securesourcemanagerrepositoryfull.golden.yaml new file mode 100644 index 0000000000..efad373cfc --- /dev/null +++ b/pkg/test/resourcefixture/testdata/basic/securesourcemanager/securesourcemanagerrepository/securesourcemanagerrepositoryfull/_generated_object_securesourcemanagerrepositoryfull.golden.yaml @@ -0,0 +1,37 @@ +apiVersion: securesourcemanager.cnrm.cloud.google.com/v1alpha1 +kind: SecureSourceManagerRepository +metadata: + finalizers: + - cnrm.cloud.google.com/finalizer + - cnrm.cloud.google.com/deletion-defender + generation: 1 + labels: + cnrm-test: "true" + name: ssmrepository-${uniqueId} + namespace: ${uniqueId} +spec: + initialConfig: + defaultBranch: main + gitignores: + - python + license: mit + readme: default + instanceRef: + name: ssminstance-dep-${uniqueId} + location: us-central1 + projectRef: + external: ${projectId} +status: + conditions: + - lastTransitionTime: "1970-01-01T00:00:00Z" + message: The resource is up to date + reason: UpToDate + status: "True" + type: Ready + externalRef: projects/${projectId}/locations/us-central1/repositories/ssmrepository-${uniqueId} + observedGeneration: 1 + observedState: + uris: + api: https://ssminstance-dep-${uniqueId}-${projectNumber}-api.us-central1.sourcemanager.dev/v1/projects/${projectId}/locations/us-central1/repositories/ssmrepository-${uniqueId} + gitHTTPS: https://ssminstance-dep-${uniqueId}-${projectNumber}-git.us-central1.sourcemanager.dev/${projectId}/ssmrepository-${uniqueId}.git + html: https://ssminstance-dep-${uniqueId}-${projectNumber}.us-central1.sourcemanager.dev/${projectId}/ssmrepository-${uniqueId} diff --git a/pkg/test/resourcefixture/testdata/basic/securesourcemanager/securesourcemanagerrepository/securesourcemanagerrepositoryfull/_http.log b/pkg/test/resourcefixture/testdata/basic/securesourcemanager/securesourcemanagerrepository/securesourcemanagerrepositoryfull/_http.log new file mode 100644 index 0000000000..3955a201fd --- /dev/null +++ b/pkg/test/resourcefixture/testdata/basic/securesourcemanager/securesourcemanagerrepository/securesourcemanagerrepositoryfull/_http.log @@ -0,0 +1,377 @@ +GET https://securesourcemanager.googleapis.com/v1/projects/${projectId}/locations/us-central1/instances/ssminstance-dep-${uniqueId}?%24alt=json%3Benum-encoding%3Dint +Content-Type: application/json +User-Agent: kcc/controller-manager +x-goog-request-params: name=projects%2F${projectId}%2Flocations%2Fus-central1%2Finstances%2Fssminstance-dep-${uniqueId} + +404 Not Found +Cache-Control: private +Content-Type: application/json; charset=UTF-8 +Server: ESF +Vary: Origin +Vary: X-Origin +Vary: Referer +X-Content-Type-Options: nosniff +X-Frame-Options: SAMEORIGIN +X-Xss-Protection: 0 + +{ + "error": { + "code": 404, + "message": "Resource 'projects/${projectId}/locations/us-central1/instances/ssminstance-dep-${uniqueId}' was not found", + "status": "NOT_FOUND" + } +} + +--- + +POST https://securesourcemanager.googleapis.com/v1/projects/${projectId}/locations/us-central1/instances?%24alt=json%3Benum-encoding%3Dint&instanceId=ssminstance-dep-${uniqueId} +Content-Type: application/json +User-Agent: kcc/controller-manager +x-goog-request-params: parent=projects%2F${projectId}%2Flocations%2Fus-central1 + +{} + +200 OK +Cache-Control: private +Content-Type: application/json; charset=UTF-8 +Server: ESF +Vary: Origin +Vary: X-Origin +Vary: Referer +X-Content-Type-Options: nosniff +X-Frame-Options: SAMEORIGIN +X-Xss-Protection: 0 + +{ + "metadata": { + "@type": "type.googleapis.com/google.cloud.securesourcemanager.v1.OperationMetadata", + "apiVersion": "v1", + "createTime": "2024-04-01T12:34:56.123456Z", + "target": "projects/${projectId}/locations/us-central1/instances/ssminstance-dep-${uniqueId}", + "verb": "create" + }, + "name": "projects/${projectId}/locations/us-central1/operations/${operationID}" +} + +--- + +GET https://securesourcemanager.googleapis.com/v1/projects/${projectId}/locations/us-central1/operations/${operationID} +Content-Type: application/json +User-Agent: kcc/controller-manager +x-goog-request-params: name=projects%2F${projectId}%2Flocations%2Fus-central1%2Foperations%2F${operationID} + +200 OK +Cache-Control: private +Content-Type: application/json; charset=UTF-8 +Server: ESF +Vary: Origin +Vary: X-Origin +Vary: Referer +X-Content-Type-Options: nosniff +X-Frame-Options: SAMEORIGIN +X-Xss-Protection: 0 + +{ + "done": true, + "metadata": { + "@type": "type.googleapis.com/google.cloud.securesourcemanager.v1.OperationMetadata", + "apiVersion": "v1", + "createTime": "2024-04-01T12:34:56.123456Z", + "endTime": "2024-04-01T12:34:56.123456Z", + "target": "projects/${projectId}/locations/us-central1/instances/ssminstance-dep-${uniqueId}", + "verb": "create" + }, + "name": "projects/${projectId}/locations/us-central1/operations/${operationID}", + "response": { + "@type": "type.googleapis.com/google.cloud.securesourcemanager.v1.Instance", + "createTime": "2024-04-01T12:34:56.123456Z", + "hostConfig": { + "api": "ssminstance-dep-${uniqueId}-${projectNumber}-api.us-central1.sourcemanager.dev", + "gitHttp": "ssminstance-dep-${uniqueId}-${projectNumber}-git.us-central1.sourcemanager.dev", + "gitSsh": "ssminstance-dep-${uniqueId}-${projectNumber}-ssh.us-central1.sourcemanager.dev", + "html": "ssminstance-dep-${uniqueId}-${projectNumber}.us-central1.sourcemanager.dev" + }, + "name": "projects/${projectId}/locations/us-central1/instances/ssminstance-dep-${uniqueId}", + "state": "ACTIVE", + "updateTime": "2024-04-01T12:34:56.123456Z" + } +} + +--- + +GET https://securesourcemanager.googleapis.com/v1/projects/${projectId}/locations/us-central1/repositories/ssmrepository-${uniqueId}?%24alt=json%3Benum-encoding%3Dint +Content-Type: application/json +User-Agent: kcc/controller-manager +x-goog-request-params: name=projects%2F${projectId}%2Flocations%2Fus-central1%2Frepositories%2Fssmrepository-${uniqueId} + +404 Not Found +Cache-Control: private +Content-Type: application/json; charset=UTF-8 +Server: ESF +Vary: Origin +Vary: X-Origin +Vary: Referer +X-Content-Type-Options: nosniff +X-Frame-Options: SAMEORIGIN +X-Xss-Protection: 0 + +{ + "error": { + "code": 404, + "message": "Resource 'projects/${projectId}/locations/us-central1/repositories/ssmrepository-${uniqueId}' was not found", + "status": "NOT_FOUND" + } +} + +--- + +POST https://securesourcemanager.googleapis.com/v1/projects/${projectId}/locations/us-central1/repositories?%24alt=json%3Benum-encoding%3Dint&repositoryId=ssmrepository-${uniqueId} +Content-Type: application/json +User-Agent: kcc/controller-manager +x-goog-request-params: parent=projects%2F${projectId}%2Flocations%2Fus-central1 + +{ + "initialConfig": { + "defaultBranch": "main", + "gitignores": [ + "python" + ], + "license": "mit", + "readme": "default" + }, + "instance": "projects/${projectId}/locations/us-central1/instances/ssminstance-dep-${uniqueId}" +} + +200 OK +Cache-Control: private +Content-Type: application/json; charset=UTF-8 +Server: ESF +Vary: Origin +Vary: X-Origin +Vary: Referer +X-Content-Type-Options: nosniff +X-Frame-Options: SAMEORIGIN +X-Xss-Protection: 0 + +{ + "metadata": { + "@type": "type.googleapis.com/google.cloud.securesourcemanager.v1.OperationMetadata", + "apiVersion": "v1", + "createTime": "2024-04-01T12:34:56.123456Z", + "target": "projects/${projectId}/locations/us-central1/repositories/ssmrepository-${uniqueId}", + "verb": "create" + }, + "name": "projects/${projectId}/locations/us-central1/operations/${operationID}" +} + +--- + +GET https://securesourcemanager.googleapis.com/v1/projects/${projectId}/locations/us-central1/operations/${operationID} +Content-Type: application/json +User-Agent: kcc/controller-manager +x-goog-request-params: name=projects%2F${projectId}%2Flocations%2Fus-central1%2Foperations%2F${operationID} + +200 OK +Cache-Control: private +Content-Type: application/json; charset=UTF-8 +Server: ESF +Vary: Origin +Vary: X-Origin +Vary: Referer +X-Content-Type-Options: nosniff +X-Frame-Options: SAMEORIGIN +X-Xss-Protection: 0 + +{ + "done": true, + "metadata": { + "@type": "type.googleapis.com/google.cloud.securesourcemanager.v1.OperationMetadata", + "apiVersion": "v1", + "createTime": "2024-04-01T12:34:56.123456Z", + "endTime": "2024-04-01T12:34:56.123456Z", + "target": "projects/${projectId}/locations/us-central1/repositories/ssmrepository-${uniqueId}", + "verb": "create" + }, + "name": "projects/${projectId}/locations/us-central1/operations/${operationID}", + "response": { + "@type": "type.googleapis.com/google.cloud.securesourcemanager.v1.Repository", + "createTime": "2024-04-01T12:34:56.123456Z", + "initialConfig": { + "defaultBranch": "main", + "gitignores": [ + "python" + ], + "license": "mit", + "readme": "default" + }, + "instance": "projects/${projectId}/locations/us-central1/instances/ssminstance-dep-${uniqueId}", + "name": "projects/${projectId}/locations/us-central1/repositories/ssmrepository-${uniqueId}", + "updateTime": "2024-04-01T12:34:56.123456Z", + "uris": { + "api": "https://ssminstance-dep-${uniqueId}-${projectNumber}-api.us-central1.sourcemanager.dev/v1/projects/${projectId}/locations/us-central1/repositories/ssmrepository-${uniqueId}", + "gitHttps": "https://ssminstance-dep-${uniqueId}-${projectNumber}-git.us-central1.sourcemanager.dev/${projectId}/ssmrepository-${uniqueId}.git", + "html": "https://ssminstance-dep-${uniqueId}-${projectNumber}.us-central1.sourcemanager.dev/${projectId}/ssmrepository-${uniqueId}" + } + } +} + +--- + +GET https://securesourcemanager.googleapis.com/v1/projects/${projectId}/locations/us-central1/repositories/ssmrepository-${uniqueId}?%24alt=json%3Benum-encoding%3Dint +Content-Type: application/json +User-Agent: kcc/controller-manager +x-goog-request-params: name=projects%2F${projectId}%2Flocations%2Fus-central1%2Frepositories%2Fssmrepository-${uniqueId} + +200 OK +Cache-Control: private +Content-Type: application/json; charset=UTF-8 +Server: ESF +Vary: Origin +Vary: X-Origin +Vary: Referer +X-Content-Type-Options: nosniff +X-Frame-Options: SAMEORIGIN +X-Xss-Protection: 0 + +{ + "createTime": "2024-04-01T12:34:56.123456Z", + "initialConfig": { + "defaultBranch": "main", + "gitignores": [ + "python" + ], + "license": "mit", + "readme": "default" + }, + "instance": "projects/${projectId}/locations/us-central1/instances/ssminstance-dep-${uniqueId}", + "name": "projects/${projectId}/locations/us-central1/repositories/ssmrepository-${uniqueId}", + "updateTime": "2024-04-01T12:34:56.123456Z", + "uris": { + "api": "https://ssminstance-dep-${uniqueId}-${projectNumber}-api.us-central1.sourcemanager.dev/v1/projects/${projectId}/locations/us-central1/repositories/ssmrepository-${uniqueId}", + "gitHttps": "https://ssminstance-dep-${uniqueId}-${projectNumber}-git.us-central1.sourcemanager.dev/${projectId}/ssmrepository-${uniqueId}.git", + "html": "https://ssminstance-dep-${uniqueId}-${projectNumber}.us-central1.sourcemanager.dev/${projectId}/ssmrepository-${uniqueId}" + } +} + +--- + +DELETE https://securesourcemanager.googleapis.com/v1/projects/${projectId}/locations/us-central1/repositories/ssmrepository-${uniqueId}?%24alt=json%3Benum-encoding%3Dint +Content-Type: application/json +User-Agent: kcc/controller-manager +x-goog-request-params: name=projects%2F${projectId}%2Flocations%2Fus-central1%2Frepositories%2Fssmrepository-${uniqueId} + +200 OK +Cache-Control: private +Content-Type: application/json; charset=UTF-8 +Server: ESF +Vary: Origin +Vary: X-Origin +Vary: Referer +X-Content-Type-Options: nosniff +X-Frame-Options: SAMEORIGIN +X-Xss-Protection: 0 + +{ + "metadata": { + "@type": "type.googleapis.com/google.cloud.securesourcemanager.v1.OperationMetadata", + "apiVersion": "v1", + "createTime": "2024-04-01T12:34:56.123456Z", + "target": "projects/${projectId}/locations/us-central1/repositories/ssmrepository-${uniqueId}", + "verb": "delete" + }, + "name": "projects/${projectId}/locations/us-central1/operations/${operationID}" +} + +--- + +GET https://securesourcemanager.googleapis.com/v1/projects/${projectId}/locations/us-central1/instances/ssminstance-dep-${uniqueId}?%24alt=json%3Benum-encoding%3Dint +Content-Type: application/json +User-Agent: kcc/controller-manager +x-goog-request-params: name=projects%2F${projectId}%2Flocations%2Fus-central1%2Finstances%2Fssminstance-dep-${uniqueId} + +200 OK +Cache-Control: private +Content-Type: application/json; charset=UTF-8 +Server: ESF +Vary: Origin +Vary: X-Origin +Vary: Referer +X-Content-Type-Options: nosniff +X-Frame-Options: SAMEORIGIN +X-Xss-Protection: 0 + +{ + "createTime": "2024-04-01T12:34:56.123456Z", + "hostConfig": { + "api": "ssminstance-dep-${uniqueId}-${projectNumber}-api.us-central1.sourcemanager.dev", + "gitHttp": "ssminstance-dep-${uniqueId}-${projectNumber}-git.us-central1.sourcemanager.dev", + "gitSsh": "ssminstance-dep-${uniqueId}-${projectNumber}-ssh.us-central1.sourcemanager.dev", + "html": "ssminstance-dep-${uniqueId}-${projectNumber}.us-central1.sourcemanager.dev" + }, + "name": "projects/${projectId}/locations/us-central1/instances/ssminstance-dep-${uniqueId}", + "state": 2, + "updateTime": "2024-04-01T12:34:56.123456Z" +} + +--- + +DELETE https://securesourcemanager.googleapis.com/v1/projects/${projectId}/locations/us-central1/instances/ssminstance-dep-${uniqueId}?%24alt=json%3Benum-encoding%3Dint +Content-Type: application/json +User-Agent: kcc/controller-manager +x-goog-request-params: name=projects%2F${projectId}%2Flocations%2Fus-central1%2Finstances%2Fssminstance-dep-${uniqueId} + +200 OK +Cache-Control: private +Content-Type: application/json; charset=UTF-8 +Server: ESF +Vary: Origin +Vary: X-Origin +Vary: Referer +X-Content-Type-Options: nosniff +X-Frame-Options: SAMEORIGIN +X-Xss-Protection: 0 + +{ + "metadata": { + "@type": "type.googleapis.com/google.cloud.securesourcemanager.v1.OperationMetadata", + "apiVersion": "v1", + "createTime": "2024-04-01T12:34:56.123456Z", + "target": "projects/${projectId}/locations/us-central1/instances/ssminstance-dep-${uniqueId}", + "verb": "delete" + }, + "name": "projects/${projectId}/locations/us-central1/operations/${operationID}" +} + +--- + +GET https://securesourcemanager.googleapis.com/v1/projects/${projectId}/locations/us-central1/operations/${operationID} +Content-Type: application/json +User-Agent: kcc/controller-manager +x-goog-request-params: name=projects%2F${projectId}%2Flocations%2Fus-central1%2Foperations%2F${operationID} + +200 OK +Cache-Control: private +Content-Type: application/json; charset=UTF-8 +Server: ESF +Vary: Origin +Vary: X-Origin +Vary: Referer +X-Content-Type-Options: nosniff +X-Frame-Options: SAMEORIGIN +X-Xss-Protection: 0 + +{ + "done": true, + "metadata": { + "@type": "type.googleapis.com/google.cloud.securesourcemanager.v1.OperationMetadata", + "apiVersion": "v1", + "createTime": "2024-04-01T12:34:56.123456Z", + "endTime": "2024-04-01T12:34:56.123456Z", + "target": "projects/${projectId}/locations/us-central1/instances/ssminstance-dep-${uniqueId}", + "verb": "delete" + }, + "name": "projects/${projectId}/locations/us-central1/operations/${operationID}", + "response": { + "@type": "type.googleapis.com/google.protobuf.Empty" + } +} \ No newline at end of file diff --git a/pkg/test/resourcefixture/testdata/basic/securesourcemanager/securesourcemanagerrepository/securesourcemanagerrepositoryfull/create.yaml b/pkg/test/resourcefixture/testdata/basic/securesourcemanager/securesourcemanagerrepository/securesourcemanagerrepositoryfull/create.yaml new file mode 100644 index 0000000000..dfaccfe948 --- /dev/null +++ b/pkg/test/resourcefixture/testdata/basic/securesourcemanager/securesourcemanagerrepository/securesourcemanagerrepositoryfull/create.yaml @@ -0,0 +1,30 @@ +# Copyright 2024 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +apiVersion: securesourcemanager.cnrm.cloud.google.com/v1alpha1 +kind: SecureSourceManagerRepository +metadata: + name: ssmrepository-${uniqueId} +spec: + location: us-central1 + projectRef: + external: ${projectId} + instanceRef: + name: ssminstance-dep-${uniqueId} + initialConfig: + defaultBranch: main + gitignores: + - python + license: mit + readme: default \ No newline at end of file diff --git a/pkg/test/resourcefixture/testdata/basic/securesourcemanager/securesourcemanagerrepository/securesourcemanagerrepositoryfull/dependencies.yaml b/pkg/test/resourcefixture/testdata/basic/securesourcemanager/securesourcemanagerrepository/securesourcemanagerrepositoryfull/dependencies.yaml new file mode 100644 index 0000000000..4ccd139a65 --- /dev/null +++ b/pkg/test/resourcefixture/testdata/basic/securesourcemanager/securesourcemanagerrepository/securesourcemanagerrepositoryfull/dependencies.yaml @@ -0,0 +1,22 @@ +# Copyright 2024 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +apiVersion: securesourcemanager.cnrm.cloud.google.com/v1alpha1 +kind: SecureSourceManagerInstance +metadata: + name: ssminstance-dep-${uniqueId} +spec: + location: us-central1 + projectRef: + external: ${projectId}