use common secure values
This commit is contained in:
@@ -0,0 +1,94 @@
|
||||
package v0alpha1
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
const redacted = "[REDACTED]"
|
||||
|
||||
// RawSecureValue contains the raw decrypted secure value.
|
||||
type RawSecureValue string
|
||||
|
||||
var (
|
||||
_ fmt.Stringer = (*RawSecureValue)(nil)
|
||||
_ fmt.Formatter = (*RawSecureValue)(nil)
|
||||
_ fmt.GoStringer = (*RawSecureValue)(nil)
|
||||
_ json.Marshaler = (*RawSecureValue)(nil)
|
||||
_ yaml.Marshaler = (*RawSecureValue)(nil)
|
||||
)
|
||||
|
||||
// Allow access to a secure value inside
|
||||
// +k8s:openapi-gen=true
|
||||
type InlineSecureValue struct {
|
||||
// Create a secure value -- this is only used for POST/PUT
|
||||
// +k8s:validation:minLength=1
|
||||
// +k8s:validation:maxLength=24576
|
||||
Create RawSecureValue `json:"create,omitempty"`
|
||||
|
||||
// Name in the secret service (reference)
|
||||
Name string `json:"name,omitempty"`
|
||||
|
||||
// Remove this value from the secure value map
|
||||
// Values owned by this resource will be deleted if necessary
|
||||
Remove bool `json:"remove,omitempty,omitzero"`
|
||||
}
|
||||
|
||||
func (v InlineSecureValue) IsZero() bool {
|
||||
return v.Create.IsZero() && v.Name == "" && !v.Remove
|
||||
}
|
||||
|
||||
// Collection of secure values
|
||||
// +k8s:openapi-gen=true
|
||||
type InlineSecureValues = map[string]InlineSecureValue
|
||||
|
||||
// NewSecretValue creates a new exposed secure value wrapper.
|
||||
func NewSecretValue(v string) RawSecureValue {
|
||||
return RawSecureValue(v)
|
||||
}
|
||||
|
||||
// DangerouslyExposeAndConsumeValue will move the decrypted secure value out of the wrapper and return it.
|
||||
// Further attempts to call this method will panic.
|
||||
// The function name is intentionally kept long and weird because this is a dangerous operation and should be used carefully!
|
||||
func (s *RawSecureValue) DangerouslyExposeAndConsumeValue() string {
|
||||
if *s == "" {
|
||||
panic("underlying value is empty or was consumed")
|
||||
}
|
||||
|
||||
tmp := *s
|
||||
*s = ""
|
||||
|
||||
return string(tmp)
|
||||
}
|
||||
|
||||
func (s RawSecureValue) IsZero() bool {
|
||||
return s == "" // exclude from JSON
|
||||
}
|
||||
|
||||
// String must not return the exposed secure value.
|
||||
func (s RawSecureValue) String() string {
|
||||
return redacted
|
||||
}
|
||||
|
||||
// Format must not return the exposed secure value.
|
||||
func (s RawSecureValue) Format(f fmt.State, _verb rune) {
|
||||
_, _ = fmt.Fprint(f, redacted)
|
||||
}
|
||||
|
||||
// GoString must not return the exposed secure value.
|
||||
func (s RawSecureValue) GoString() string {
|
||||
return redacted
|
||||
}
|
||||
|
||||
// MarshalJSON must not return the exposed secure value.
|
||||
func (s RawSecureValue) MarshalJSON() ([]byte, error) {
|
||||
return []byte(strconv.Quote(redacted)), nil
|
||||
}
|
||||
|
||||
// MarshalYAML must not return the exposed secure value.
|
||||
func (s RawSecureValue) MarshalYAML() (any, error) {
|
||||
return redacted, nil
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
package v0alpha1
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
func TestSecureValues(t *testing.T) {
|
||||
expected := "[REDACTED]"
|
||||
|
||||
rawValue := "a-password"
|
||||
esv := NewSecretValue(rawValue)
|
||||
|
||||
// String must not return the exposed secure value.
|
||||
require.Equal(t, expected, esv.String())
|
||||
|
||||
// Format/GoString must not return the exposed secure value.
|
||||
require.Equal(t, expected, fmt.Sprintf("%+#v", esv))
|
||||
require.Equal(t, expected, fmt.Sprintf("%v", esv))
|
||||
require.Equal(t, expected, fmt.Sprintf("%s", esv))
|
||||
|
||||
buf := new(bytes.Buffer)
|
||||
_, err := fmt.Fprintf(buf, "%#v", esv)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, expected, buf.String())
|
||||
|
||||
// MarshalJSON must not return the exposed secure value.
|
||||
bytes, err := json.Marshal(esv)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, `"`+expected+`"`, string(bytes))
|
||||
|
||||
// MarshalYAML must not return the exposed secure value.
|
||||
bytes, err = yaml.Marshal(esv)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, "'"+expected+"'\n", string(bytes))
|
||||
|
||||
// DangerouslyExposeAndConsumeValue returns the raw value.
|
||||
require.Equal(t, rawValue, esv.DangerouslyExposeAndConsumeValue())
|
||||
|
||||
// Further calls to DangerouslyExposeAndConsumeValue will panic.
|
||||
require.Panics(t, func() { esv.DangerouslyExposeAndConsumeValue() })
|
||||
}
|
||||
@@ -11,6 +11,22 @@ import (
|
||||
runtime "k8s.io/apimachinery/pkg/runtime"
|
||||
)
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *InlineSecureValue) DeepCopyInto(out *InlineSecureValue) {
|
||||
*out = *in
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new InlineSecureValue.
|
||||
func (in *InlineSecureValue) DeepCopy() *InlineSecureValue {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(InlineSecureValue)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *ObjectReference) DeepCopyInto(out *ObjectReference) {
|
||||
*out = *in
|
||||
|
||||
@@ -11,68 +11,106 @@ import (
|
||||
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
common "k8s.io/kube-openapi/pkg/common"
|
||||
spec "k8s.io/kube-openapi/pkg/validation/spec"
|
||||
ptr "k8s.io/utils/ptr"
|
||||
)
|
||||
|
||||
func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenAPIDefinition {
|
||||
return map[string]common.OpenAPIDefinition{
|
||||
"github.com/grafana/grafana/pkg/apimachinery/apis/common/v0alpha1.ObjectReference": schema_apimachinery_apis_common_v0alpha1_ObjectReference(ref),
|
||||
"github.com/grafana/grafana/pkg/apimachinery/apis/common/v0alpha1.Scope": schema_apimachinery_apis_common_v0alpha1_Scope(ref),
|
||||
"github.com/grafana/grafana/pkg/apimachinery/apis/common/v0alpha1.ScopeFilter": schema_apimachinery_apis_common_v0alpha1_ScopeFilter(ref),
|
||||
"github.com/grafana/grafana/pkg/apimachinery/apis/common/v0alpha1.ScopeSpec": schema_apimachinery_apis_common_v0alpha1_ScopeSpec(ref),
|
||||
"github.com/grafana/grafana/pkg/apimachinery/apis/common/v0alpha1.Unstructured": Unstructured{}.OpenAPIDefinition(),
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1.APIGroup": schema_pkg_apis_meta_v1_APIGroup(ref),
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1.APIGroupList": schema_pkg_apis_meta_v1_APIGroupList(ref),
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1.APIResource": schema_pkg_apis_meta_v1_APIResource(ref),
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1.APIResourceList": schema_pkg_apis_meta_v1_APIResourceList(ref),
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1.APIVersions": schema_pkg_apis_meta_v1_APIVersions(ref),
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1.ApplyOptions": schema_pkg_apis_meta_v1_ApplyOptions(ref),
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1.Condition": schema_pkg_apis_meta_v1_Condition(ref),
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1.CreateOptions": schema_pkg_apis_meta_v1_CreateOptions(ref),
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1.DeleteOptions": schema_pkg_apis_meta_v1_DeleteOptions(ref),
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1.Duration": schema_pkg_apis_meta_v1_Duration(ref),
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1.FieldSelectorRequirement": schema_pkg_apis_meta_v1_FieldSelectorRequirement(ref),
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1.FieldsV1": schema_pkg_apis_meta_v1_FieldsV1(ref),
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1.GetOptions": schema_pkg_apis_meta_v1_GetOptions(ref),
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1.GroupKind": schema_pkg_apis_meta_v1_GroupKind(ref),
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1.GroupResource": schema_pkg_apis_meta_v1_GroupResource(ref),
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1.GroupVersion": schema_pkg_apis_meta_v1_GroupVersion(ref),
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1.GroupVersionForDiscovery": schema_pkg_apis_meta_v1_GroupVersionForDiscovery(ref),
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1.GroupVersionKind": schema_pkg_apis_meta_v1_GroupVersionKind(ref),
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1.GroupVersionResource": schema_pkg_apis_meta_v1_GroupVersionResource(ref),
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1.InternalEvent": schema_pkg_apis_meta_v1_InternalEvent(ref),
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1.LabelSelector": schema_pkg_apis_meta_v1_LabelSelector(ref),
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1.LabelSelectorRequirement": schema_pkg_apis_meta_v1_LabelSelectorRequirement(ref),
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1.List": schema_pkg_apis_meta_v1_List(ref),
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta": schema_pkg_apis_meta_v1_ListMeta(ref),
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1.ListOptions": schema_pkg_apis_meta_v1_ListOptions(ref),
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1.ManagedFieldsEntry": schema_pkg_apis_meta_v1_ManagedFieldsEntry(ref),
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1.MicroTime": schema_pkg_apis_meta_v1_MicroTime(ref),
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta": schema_pkg_apis_meta_v1_ObjectMeta(ref),
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1.OwnerReference": schema_pkg_apis_meta_v1_OwnerReference(ref),
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1.PartialObjectMetadata": schema_pkg_apis_meta_v1_PartialObjectMetadata(ref),
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1.PartialObjectMetadataList": schema_pkg_apis_meta_v1_PartialObjectMetadataList(ref),
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1.Patch": schema_pkg_apis_meta_v1_Patch(ref),
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1.PatchOptions": schema_pkg_apis_meta_v1_PatchOptions(ref),
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1.Preconditions": schema_pkg_apis_meta_v1_Preconditions(ref),
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1.RootPaths": schema_pkg_apis_meta_v1_RootPaths(ref),
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1.ServerAddressByClientCIDR": schema_pkg_apis_meta_v1_ServerAddressByClientCIDR(ref),
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1.Status": schema_pkg_apis_meta_v1_Status(ref),
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1.StatusCause": schema_pkg_apis_meta_v1_StatusCause(ref),
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1.StatusDetails": schema_pkg_apis_meta_v1_StatusDetails(ref),
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1.Table": schema_pkg_apis_meta_v1_Table(ref),
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1.TableColumnDefinition": schema_pkg_apis_meta_v1_TableColumnDefinition(ref),
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1.TableOptions": schema_pkg_apis_meta_v1_TableOptions(ref),
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1.TableRow": schema_pkg_apis_meta_v1_TableRow(ref),
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1.TableRowCondition": schema_pkg_apis_meta_v1_TableRowCondition(ref),
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1.Time": schema_pkg_apis_meta_v1_Time(ref),
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1.Timestamp": schema_pkg_apis_meta_v1_Timestamp(ref),
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1.TypeMeta": schema_pkg_apis_meta_v1_TypeMeta(ref),
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1.UpdateOptions": schema_pkg_apis_meta_v1_UpdateOptions(ref),
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1.WatchEvent": schema_pkg_apis_meta_v1_WatchEvent(ref),
|
||||
"k8s.io/apimachinery/pkg/runtime.RawExtension": schema_k8sio_apimachinery_pkg_runtime_RawExtension(ref),
|
||||
"k8s.io/apimachinery/pkg/runtime.TypeMeta": schema_k8sio_apimachinery_pkg_runtime_TypeMeta(ref),
|
||||
"k8s.io/apimachinery/pkg/runtime.Unknown": schema_k8sio_apimachinery_pkg_runtime_Unknown(ref),
|
||||
"k8s.io/apimachinery/pkg/version.Info": schema_k8sio_apimachinery_pkg_version_Info(ref),
|
||||
"github.com/grafana/grafana/pkg/apimachinery/apis/common/v0alpha1.InlineSecureValue": schema_apimachinery_apis_common_v0alpha1_InlineSecureValue(ref),
|
||||
"github.com/grafana/grafana/pkg/apimachinery/apis/common/v0alpha1.ObjectReference": schema_apimachinery_apis_common_v0alpha1_ObjectReference(ref),
|
||||
"github.com/grafana/grafana/pkg/apimachinery/apis/common/v0alpha1.Scope": schema_apimachinery_apis_common_v0alpha1_Scope(ref),
|
||||
"github.com/grafana/grafana/pkg/apimachinery/apis/common/v0alpha1.ScopeFilter": schema_apimachinery_apis_common_v0alpha1_ScopeFilter(ref),
|
||||
"github.com/grafana/grafana/pkg/apimachinery/apis/common/v0alpha1.ScopeSpec": schema_apimachinery_apis_common_v0alpha1_ScopeSpec(ref),
|
||||
"github.com/grafana/grafana/pkg/apimachinery/apis/common/v0alpha1.Unstructured": Unstructured{}.OpenAPIDefinition(),
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1.APIGroup": schema_pkg_apis_meta_v1_APIGroup(ref),
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1.APIGroupList": schema_pkg_apis_meta_v1_APIGroupList(ref),
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1.APIResource": schema_pkg_apis_meta_v1_APIResource(ref),
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1.APIResourceList": schema_pkg_apis_meta_v1_APIResourceList(ref),
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1.APIVersions": schema_pkg_apis_meta_v1_APIVersions(ref),
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1.ApplyOptions": schema_pkg_apis_meta_v1_ApplyOptions(ref),
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1.Condition": schema_pkg_apis_meta_v1_Condition(ref),
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1.CreateOptions": schema_pkg_apis_meta_v1_CreateOptions(ref),
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1.DeleteOptions": schema_pkg_apis_meta_v1_DeleteOptions(ref),
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1.Duration": schema_pkg_apis_meta_v1_Duration(ref),
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1.FieldSelectorRequirement": schema_pkg_apis_meta_v1_FieldSelectorRequirement(ref),
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1.FieldsV1": schema_pkg_apis_meta_v1_FieldsV1(ref),
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1.GetOptions": schema_pkg_apis_meta_v1_GetOptions(ref),
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1.GroupKind": schema_pkg_apis_meta_v1_GroupKind(ref),
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1.GroupResource": schema_pkg_apis_meta_v1_GroupResource(ref),
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1.GroupVersion": schema_pkg_apis_meta_v1_GroupVersion(ref),
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1.GroupVersionForDiscovery": schema_pkg_apis_meta_v1_GroupVersionForDiscovery(ref),
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1.GroupVersionKind": schema_pkg_apis_meta_v1_GroupVersionKind(ref),
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1.GroupVersionResource": schema_pkg_apis_meta_v1_GroupVersionResource(ref),
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1.InternalEvent": schema_pkg_apis_meta_v1_InternalEvent(ref),
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1.LabelSelector": schema_pkg_apis_meta_v1_LabelSelector(ref),
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1.LabelSelectorRequirement": schema_pkg_apis_meta_v1_LabelSelectorRequirement(ref),
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1.List": schema_pkg_apis_meta_v1_List(ref),
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta": schema_pkg_apis_meta_v1_ListMeta(ref),
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1.ListOptions": schema_pkg_apis_meta_v1_ListOptions(ref),
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1.ManagedFieldsEntry": schema_pkg_apis_meta_v1_ManagedFieldsEntry(ref),
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1.MicroTime": schema_pkg_apis_meta_v1_MicroTime(ref),
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta": schema_pkg_apis_meta_v1_ObjectMeta(ref),
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1.OwnerReference": schema_pkg_apis_meta_v1_OwnerReference(ref),
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1.PartialObjectMetadata": schema_pkg_apis_meta_v1_PartialObjectMetadata(ref),
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1.PartialObjectMetadataList": schema_pkg_apis_meta_v1_PartialObjectMetadataList(ref),
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1.Patch": schema_pkg_apis_meta_v1_Patch(ref),
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1.PatchOptions": schema_pkg_apis_meta_v1_PatchOptions(ref),
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1.Preconditions": schema_pkg_apis_meta_v1_Preconditions(ref),
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1.RootPaths": schema_pkg_apis_meta_v1_RootPaths(ref),
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1.ServerAddressByClientCIDR": schema_pkg_apis_meta_v1_ServerAddressByClientCIDR(ref),
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1.Status": schema_pkg_apis_meta_v1_Status(ref),
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1.StatusCause": schema_pkg_apis_meta_v1_StatusCause(ref),
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1.StatusDetails": schema_pkg_apis_meta_v1_StatusDetails(ref),
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1.Table": schema_pkg_apis_meta_v1_Table(ref),
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1.TableColumnDefinition": schema_pkg_apis_meta_v1_TableColumnDefinition(ref),
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1.TableOptions": schema_pkg_apis_meta_v1_TableOptions(ref),
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1.TableRow": schema_pkg_apis_meta_v1_TableRow(ref),
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1.TableRowCondition": schema_pkg_apis_meta_v1_TableRowCondition(ref),
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1.Time": schema_pkg_apis_meta_v1_Time(ref),
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1.Timestamp": schema_pkg_apis_meta_v1_Timestamp(ref),
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1.TypeMeta": schema_pkg_apis_meta_v1_TypeMeta(ref),
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1.UpdateOptions": schema_pkg_apis_meta_v1_UpdateOptions(ref),
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1.WatchEvent": schema_pkg_apis_meta_v1_WatchEvent(ref),
|
||||
"k8s.io/apimachinery/pkg/runtime.RawExtension": schema_k8sio_apimachinery_pkg_runtime_RawExtension(ref),
|
||||
"k8s.io/apimachinery/pkg/runtime.TypeMeta": schema_k8sio_apimachinery_pkg_runtime_TypeMeta(ref),
|
||||
"k8s.io/apimachinery/pkg/runtime.Unknown": schema_k8sio_apimachinery_pkg_runtime_Unknown(ref),
|
||||
"k8s.io/apimachinery/pkg/version.Info": schema_k8sio_apimachinery_pkg_version_Info(ref),
|
||||
}
|
||||
}
|
||||
|
||||
func schema_apimachinery_apis_common_v0alpha1_InlineSecureValue(ref common.ReferenceCallback) common.OpenAPIDefinition {
|
||||
return common.OpenAPIDefinition{
|
||||
Schema: spec.Schema{
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "Allow access to a secure value inside",
|
||||
Type: []string{"object"},
|
||||
Properties: map[string]spec.Schema{
|
||||
"create": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "Create a secure value -- this is only used for POST/PUT",
|
||||
MinLength: ptr.To[int64](1),
|
||||
MaxLength: ptr.To[int64](24576),
|
||||
Type: []string{"string"},
|
||||
Format: "",
|
||||
},
|
||||
},
|
||||
"name": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "Name in the secret service (reference)",
|
||||
Type: []string{"string"},
|
||||
Format: "",
|
||||
},
|
||||
},
|
||||
"remove": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "Remove this value from the secure value map Values owned by this resource will be deleted if necessary",
|
||||
Type: []string{"boolean"},
|
||||
Format: "",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -7,9 +7,11 @@ require (
|
||||
github.com/grafana/authlib v0.0.0-20250618124654-54543efcfeed // @grafana/identity-access-team
|
||||
github.com/grafana/authlib/types v0.0.0-20250325095148-d6da9c164a7d // @grafana/identity-access-team
|
||||
github.com/stretchr/testify v1.10.0
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
k8s.io/apimachinery v0.33.2
|
||||
k8s.io/apiserver v0.33.2
|
||||
k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff
|
||||
k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738
|
||||
)
|
||||
|
||||
require (
|
||||
@@ -48,9 +50,7 @@ require (
|
||||
google.golang.org/grpc v1.73.0 // indirect
|
||||
google.golang.org/protobuf v1.36.6 // indirect
|
||||
gopkg.in/inf.v0 v0.9.1 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
k8s.io/klog/v2 v2.130.1 // indirect
|
||||
k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738 // indirect
|
||||
sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3 // indirect
|
||||
sigs.k8s.io/randfill v1.0.0 // indirect
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.6.0 // indirect
|
||||
|
||||
@@ -12,6 +12,8 @@ import (
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
|
||||
common "github.com/grafana/grafana/pkg/apimachinery/apis/common/v0alpha1"
|
||||
)
|
||||
|
||||
// LabelKeyGetHistory is used to select object history for an given resource
|
||||
@@ -146,6 +148,12 @@ type GrafanaMetaAccessor interface {
|
||||
|
||||
// SetSourceProperties sets the source properties of the resource.
|
||||
SetSourceProperties(SourceProperties)
|
||||
|
||||
// SetSourceProperties sets the source properties of the resource.
|
||||
GetSecureValues() (common.InlineSecureValues, error)
|
||||
|
||||
// SetSourceProperties sets the source properties of the resource.
|
||||
SetSecureValues(common.InlineSecureValues) error
|
||||
}
|
||||
|
||||
var _ GrafanaMetaAccessor = (*grafanaMetaAccessor)(nil)
|
||||
@@ -821,3 +829,97 @@ func (m *grafanaMetaAccessor) SetSourceProperties(v SourceProperties) {
|
||||
|
||||
m.obj.SetAnnotations(annot)
|
||||
}
|
||||
|
||||
// GetSecureValues implements GrafanaMetaAccessor.
|
||||
func (m *grafanaMetaAccessor) GetSecureValues() (vals common.InlineSecureValues, err error) {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
err = fmt.Errorf("error reading spec")
|
||||
}
|
||||
}()
|
||||
|
||||
var property any // may be map or struct
|
||||
|
||||
f := m.r.FieldByName("Secure")
|
||||
if f.IsValid() {
|
||||
property = f.Interface()
|
||||
} else {
|
||||
// Unstructured
|
||||
u, ok := m.raw.(*unstructured.Unstructured)
|
||||
if ok {
|
||||
property = u.Object["secure"]
|
||||
}
|
||||
}
|
||||
|
||||
// Not found (and no error)
|
||||
if property == nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// Try directly casting the property
|
||||
vals, ok := property.(common.InlineSecureValues)
|
||||
if ok {
|
||||
return vals, nil
|
||||
}
|
||||
|
||||
// Generic map
|
||||
u, ok := property.(map[string]any)
|
||||
if ok {
|
||||
vals = make(common.InlineSecureValues, len(u))
|
||||
for k, v := range u {
|
||||
sv, ok := v.(map[string]any)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("unsupported nested secure value: %t", v)
|
||||
}
|
||||
inline := common.InlineSecureValue{}
|
||||
inline.Name, _, _ = unstructured.NestedString(sv, "name")
|
||||
inline.Remove, _, _ = unstructured.NestedBool(sv, "remove")
|
||||
create, _, _ := unstructured.NestedString(sv, "create")
|
||||
if create != "" {
|
||||
inline.Create = common.NewSecretValue(create)
|
||||
}
|
||||
vals[k] = inline
|
||||
}
|
||||
return vals, nil
|
||||
}
|
||||
|
||||
fmt.Printf("TODO PROPERTY: (%t) %+v\n", property, property)
|
||||
|
||||
return nil, fmt.Errorf("support: %t", property)
|
||||
}
|
||||
|
||||
// SetSecureValues implements GrafanaMetaAccessor.
|
||||
func (m *grafanaMetaAccessor) SetSecureValues(vals common.InlineSecureValues) (err error) {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
err = fmt.Errorf("error setting spec")
|
||||
}
|
||||
}()
|
||||
|
||||
f := m.r.FieldByName("Secure")
|
||||
if f.IsValid() && f.CanSet() {
|
||||
f.Set(reflect.ValueOf(vals))
|
||||
return
|
||||
}
|
||||
|
||||
// Unstructured object
|
||||
u, ok := m.raw.(*unstructured.Unstructured)
|
||||
if ok {
|
||||
u.Object["secure"] = vals
|
||||
return
|
||||
}
|
||||
|
||||
return fmt.Errorf("unable to set secure values on (%T)", m.raw)
|
||||
}
|
||||
|
||||
func ToObjectReference(obj GrafanaMetaAccessor) common.ObjectReference {
|
||||
gvk := obj.GetGroupVersionKind()
|
||||
return common.ObjectReference{
|
||||
APIGroup: gvk.Group,
|
||||
APIVersion: gvk.Version,
|
||||
Kind: gvk.Kind,
|
||||
Namespace: obj.GetNamespace(),
|
||||
Name: obj.GetName(),
|
||||
UID: obj.GetUID(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Code generated by mockery v2.52.4. DO NOT EDIT.
|
||||
// Code generated by mockery v2.53.4. DO NOT EDIT.
|
||||
|
||||
package utils
|
||||
|
||||
@@ -12,6 +12,8 @@ import (
|
||||
|
||||
types "k8s.io/apimachinery/pkg/types"
|
||||
|
||||
v0alpha1 "github.com/grafana/grafana/pkg/apimachinery/apis/common/v0alpha1"
|
||||
|
||||
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
@@ -1248,6 +1250,63 @@ func (_c *MockGrafanaMetaAccessor_GetRuntimeObject_Call) RunAndReturn(run func()
|
||||
return _c
|
||||
}
|
||||
|
||||
// GetSecureValues provides a mock function with no fields
|
||||
func (_m *MockGrafanaMetaAccessor) GetSecureValues() (map[string]v0alpha1.InlineSecureValue, error) {
|
||||
ret := _m.Called()
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for GetSecureValues")
|
||||
}
|
||||
|
||||
var r0 map[string]v0alpha1.InlineSecureValue
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func() (map[string]v0alpha1.InlineSecureValue, error)); ok {
|
||||
return rf()
|
||||
}
|
||||
if rf, ok := ret.Get(0).(func() map[string]v0alpha1.InlineSecureValue); ok {
|
||||
r0 = rf()
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(map[string]v0alpha1.InlineSecureValue)
|
||||
}
|
||||
}
|
||||
|
||||
if rf, ok := ret.Get(1).(func() error); ok {
|
||||
r1 = rf()
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// MockGrafanaMetaAccessor_GetSecureValues_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetSecureValues'
|
||||
type MockGrafanaMetaAccessor_GetSecureValues_Call struct {
|
||||
*mock.Call
|
||||
}
|
||||
|
||||
// GetSecureValues is a helper method to define mock.On call
|
||||
func (_e *MockGrafanaMetaAccessor_Expecter) GetSecureValues() *MockGrafanaMetaAccessor_GetSecureValues_Call {
|
||||
return &MockGrafanaMetaAccessor_GetSecureValues_Call{Call: _e.mock.On("GetSecureValues")}
|
||||
}
|
||||
|
||||
func (_c *MockGrafanaMetaAccessor_GetSecureValues_Call) Run(run func()) *MockGrafanaMetaAccessor_GetSecureValues_Call {
|
||||
_c.Call.Run(func(args mock.Arguments) {
|
||||
run()
|
||||
})
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *MockGrafanaMetaAccessor_GetSecureValues_Call) Return(_a0 map[string]v0alpha1.InlineSecureValue, _a1 error) *MockGrafanaMetaAccessor_GetSecureValues_Call {
|
||||
_c.Call.Return(_a0, _a1)
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *MockGrafanaMetaAccessor_GetSecureValues_Call) RunAndReturn(run func() (map[string]v0alpha1.InlineSecureValue, error)) *MockGrafanaMetaAccessor_GetSecureValues_Call {
|
||||
_c.Call.Return(run)
|
||||
return _c
|
||||
}
|
||||
|
||||
// GetSelfLink provides a mock function with no fields
|
||||
func (_m *MockGrafanaMetaAccessor) GetSelfLink() string {
|
||||
ret := _m.Called()
|
||||
@@ -2369,6 +2428,52 @@ func (_c *MockGrafanaMetaAccessor_SetResourceVersionInt64_Call) RunAndReturn(run
|
||||
return _c
|
||||
}
|
||||
|
||||
// SetSecureValues provides a mock function with given fields: _a0
|
||||
func (_m *MockGrafanaMetaAccessor) SetSecureValues(_a0 map[string]v0alpha1.InlineSecureValue) error {
|
||||
ret := _m.Called(_a0)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for SetSecureValues")
|
||||
}
|
||||
|
||||
var r0 error
|
||||
if rf, ok := ret.Get(0).(func(map[string]v0alpha1.InlineSecureValue) error); ok {
|
||||
r0 = rf(_a0)
|
||||
} else {
|
||||
r0 = ret.Error(0)
|
||||
}
|
||||
|
||||
return r0
|
||||
}
|
||||
|
||||
// MockGrafanaMetaAccessor_SetSecureValues_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SetSecureValues'
|
||||
type MockGrafanaMetaAccessor_SetSecureValues_Call struct {
|
||||
*mock.Call
|
||||
}
|
||||
|
||||
// SetSecureValues is a helper method to define mock.On call
|
||||
// - _a0 map[string]v0alpha1.InlineSecureValue
|
||||
func (_e *MockGrafanaMetaAccessor_Expecter) SetSecureValues(_a0 interface{}) *MockGrafanaMetaAccessor_SetSecureValues_Call {
|
||||
return &MockGrafanaMetaAccessor_SetSecureValues_Call{Call: _e.mock.On("SetSecureValues", _a0)}
|
||||
}
|
||||
|
||||
func (_c *MockGrafanaMetaAccessor_SetSecureValues_Call) Run(run func(_a0 map[string]v0alpha1.InlineSecureValue)) *MockGrafanaMetaAccessor_SetSecureValues_Call {
|
||||
_c.Call.Run(func(args mock.Arguments) {
|
||||
run(args[0].(map[string]v0alpha1.InlineSecureValue))
|
||||
})
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *MockGrafanaMetaAccessor_SetSecureValues_Call) Return(_a0 error) *MockGrafanaMetaAccessor_SetSecureValues_Call {
|
||||
_c.Call.Return(_a0)
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *MockGrafanaMetaAccessor_SetSecureValues_Call) RunAndReturn(run func(map[string]v0alpha1.InlineSecureValue) error) *MockGrafanaMetaAccessor_SetSecureValues_Call {
|
||||
_c.Call.Return(run)
|
||||
return _c
|
||||
}
|
||||
|
||||
// SetSelfLink provides a mock function with given fields: selfLink
|
||||
func (_m *MockGrafanaMetaAccessor) SetSelfLink(selfLink string) {
|
||||
_m.Called(selfLink)
|
||||
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
|
||||
common "github.com/grafana/grafana/pkg/apimachinery/apis/common/v0alpha1"
|
||||
"github.com/grafana/grafana/pkg/apimachinery/utils"
|
||||
)
|
||||
|
||||
@@ -24,6 +25,9 @@ type TestResource struct {
|
||||
|
||||
// Read/write raw status
|
||||
Status Spec `json:"status,omitempty"`
|
||||
|
||||
// Secure values as map
|
||||
Secure common.InlineSecureValues `json:"secure,omitempty"`
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
@@ -84,6 +88,9 @@ type TestResource2 struct {
|
||||
|
||||
// Exercise read/write pointer status
|
||||
Status *Spec `json:"status,omitempty"`
|
||||
|
||||
// This time defined with a strict struct
|
||||
SecureValues ExplictSecureValues `json:"secure,omitempty"`
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
@@ -112,6 +119,12 @@ func (in *TestResource2) DeepCopyObject() runtime.Object {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Spec defines model for Spec.
|
||||
type ExplictSecureValues struct {
|
||||
// Sample token value
|
||||
Prop common.InlineSecureValue `json:"token,omitempty"`
|
||||
}
|
||||
|
||||
// Spec defines model for Spec.
|
||||
type Spec2 struct{}
|
||||
|
||||
@@ -247,6 +260,15 @@ func TestMetaAccessor(t *testing.T) {
|
||||
status, err = meta.GetStatus()
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, res.Object["status"], status)
|
||||
|
||||
// Check write/read on unstructured object
|
||||
err = meta.SetSecureValues(common.InlineSecureValues{
|
||||
"a": {Name: "bbbb"},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
secure, err := meta.GetSecureValues()
|
||||
require.NoError(t, err)
|
||||
require.JSONEq(t, `{"a": {"name": "bbbb"}}`, asJSON(secure, true))
|
||||
})
|
||||
|
||||
t.Run("get and set grafana metadata (TestResource)", func(t *testing.T) {
|
||||
@@ -254,6 +276,11 @@ func TestMetaAccessor(t *testing.T) {
|
||||
Spec: Spec{
|
||||
Title: "test",
|
||||
},
|
||||
Secure: common.InlineSecureValues{
|
||||
"x": common.InlineSecureValue{
|
||||
Create: "hello",
|
||||
},
|
||||
},
|
||||
// Status is empty, but not nil!
|
||||
}
|
||||
meta, err := utils.MetaAccessor(res)
|
||||
@@ -302,6 +329,19 @@ func TestMetaAccessor(t *testing.T) {
|
||||
require.Equal(t, res.Status, status)
|
||||
require.Equal(t, "111", res.Status.Title)
|
||||
require.Equal(t, `{"title":"111"}`, asJSON(status, false))
|
||||
|
||||
// Check read/write secure values
|
||||
secure, err := meta.GetSecureValues()
|
||||
require.NoError(t, err)
|
||||
require.JSONEq(t, `{"x": {"create": "[REDACTED]"}}`, asJSON(secure, true))
|
||||
|
||||
err = meta.SetSecureValues(common.InlineSecureValues{
|
||||
"a": {Name: "bbbb"},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
secure, err = meta.GetSecureValues()
|
||||
require.NoError(t, err)
|
||||
require.JSONEq(t, `{"a": {"name": "bbbb"}}`, asJSON(secure, true))
|
||||
})
|
||||
|
||||
t.Run("get and set grafana metadata (TestResource2)", func(t *testing.T) {
|
||||
|
||||
@@ -4,7 +4,6 @@ import (
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
||||
common "github.com/grafana/grafana/pkg/apimachinery/apis/common/v0alpha1"
|
||||
secret "github.com/grafana/grafana/pkg/apis/secret/v0alpha1"
|
||||
)
|
||||
|
||||
// +k8s:deepcopy-gen=true
|
||||
@@ -18,7 +17,7 @@ type DataSource struct {
|
||||
Spec DataSourceSpec `json:"spec"`
|
||||
|
||||
// Secure values placeholder (true for fields that exist)
|
||||
Secure secret.InlineSecureValues `json:"secure,omitempty"`
|
||||
Secure common.InlineSecureValues `json:"secure,omitempty"`
|
||||
}
|
||||
|
||||
// DsAccess represents how the datasource connects to the remote service
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
package v0alpha1
|
||||
|
||||
import (
|
||||
secretv0alpha1 "github.com/grafana/grafana/pkg/apis/secret/v0alpha1"
|
||||
commonv0alpha1 "github.com/grafana/grafana/pkg/apimachinery/apis/common/v0alpha1"
|
||||
runtime "k8s.io/apimachinery/pkg/runtime"
|
||||
)
|
||||
|
||||
@@ -20,7 +20,7 @@ func (in *DataSource) DeepCopyInto(out *DataSource) {
|
||||
in.Spec.DeepCopyInto(&out.Spec)
|
||||
if in.Secure != nil {
|
||||
in, out := &in.Secure, &out.Secure
|
||||
*out = make(map[string]secretv0alpha1.InlineSecureValue, len(*in))
|
||||
*out = make(map[string]commonv0alpha1.InlineSecureValue, len(*in))
|
||||
for key, val := range *in {
|
||||
(*out)[key] = val
|
||||
}
|
||||
|
||||
@@ -63,7 +63,7 @@ func schema_pkg_apis_datasource_v0alpha1_DataSource(ref common.ReferenceCallback
|
||||
Schema: &spec.Schema{
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Default: map[string]interface{}{},
|
||||
Ref: ref("github.com/grafana/grafana/pkg/apis/secret/v0alpha1.InlineSecureValue"),
|
||||
Ref: ref("github.com/grafana/grafana/pkg/apimachinery/apis/common/v0alpha1.InlineSecureValue"),
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -74,7 +74,7 @@ func schema_pkg_apis_datasource_v0alpha1_DataSource(ref common.ReferenceCallback
|
||||
},
|
||||
},
|
||||
Dependencies: []string{
|
||||
"github.com/grafana/grafana/pkg/apis/datasource/v0alpha1.DataSourceSpec", "github.com/grafana/grafana/pkg/apis/secret/v0alpha1.InlineSecureValue", "k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"},
|
||||
"github.com/grafana/grafana/pkg/apimachinery/apis/common/v0alpha1.InlineSecureValue", "github.com/grafana/grafana/pkg/apis/datasource/v0alpha1.DataSourceSpec", "k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"},
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -40,10 +40,6 @@ func (s *ExposedSecureValue) DangerouslyExposeAndConsumeValue() string {
|
||||
return string(tmp)
|
||||
}
|
||||
|
||||
func (s ExposedSecureValue) IsZero() bool {
|
||||
return s == "" // exclude from JSON
|
||||
}
|
||||
|
||||
// String must not return the exposed secure value.
|
||||
func (s ExposedSecureValue) String() string {
|
||||
return redacted
|
||||
|
||||
@@ -6,10 +6,9 @@ import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/grafana/grafana/pkg/apis/secret/v0alpha1"
|
||||
"github.com/stretchr/testify/require"
|
||||
"gopkg.in/yaml.v3"
|
||||
|
||||
"github.com/grafana/grafana/pkg/apis/secret/v0alpha1"
|
||||
)
|
||||
|
||||
func TestExposedSecureValue(t *testing.T) {
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
package v0alpha1
|
||||
|
||||
// Access secure values inside any resource
|
||||
// +k8s:openapi-gen=true
|
||||
type InlineSecureValue struct {
|
||||
// Create a secure value -- this is only used for POST/PUT
|
||||
// +k8s:validation:minLength=1
|
||||
// +k8s:validation:maxLength=24576
|
||||
Create ExposedSecureValue `json:"create,omitempty"`
|
||||
|
||||
// Name in the secret service (reference)
|
||||
Name string `json:"name,omitempty"`
|
||||
|
||||
// The secret is shared (enterprise only)
|
||||
Shared bool `json:"shared,omitempty"`
|
||||
|
||||
// Remove this value -- cascading delete to the secret service if necessary
|
||||
Remove bool `json:"remove,omitempty,omitzero"`
|
||||
}
|
||||
|
||||
// Collection of secure values
|
||||
// +k8s:openapi-gen=true
|
||||
type InlineSecureValues = map[string]InlineSecureValue
|
||||
@@ -163,22 +163,6 @@ func (in *HashiCorpKeeperConfig) DeepCopy() *HashiCorpKeeperConfig {
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *InlineSecureValue) DeepCopyInto(out *InlineSecureValue) {
|
||||
*out = *in
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new InlineSecureValue.
|
||||
func (in *InlineSecureValue) DeepCopy() *InlineSecureValue {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(InlineSecureValue)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *Keeper) DeepCopyInto(out *Keeper) {
|
||||
*out = *in
|
||||
|
||||
@@ -24,7 +24,6 @@ func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenA
|
||||
"github.com/grafana/grafana/pkg/apis/secret/v0alpha1.GCPKeeperConfig": schema_pkg_apis_secret_v0alpha1_GCPKeeperConfig(ref),
|
||||
"github.com/grafana/grafana/pkg/apis/secret/v0alpha1.HashiCorpCredentials": schema_pkg_apis_secret_v0alpha1_HashiCorpCredentials(ref),
|
||||
"github.com/grafana/grafana/pkg/apis/secret/v0alpha1.HashiCorpKeeperConfig": schema_pkg_apis_secret_v0alpha1_HashiCorpKeeperConfig(ref),
|
||||
"github.com/grafana/grafana/pkg/apis/secret/v0alpha1.InlineSecureValue": schema_pkg_apis_secret_v0alpha1_InlineSecureValue(ref),
|
||||
"github.com/grafana/grafana/pkg/apis/secret/v0alpha1.Keeper": schema_pkg_apis_secret_v0alpha1_Keeper(ref),
|
||||
"github.com/grafana/grafana/pkg/apis/secret/v0alpha1.KeeperList": schema_pkg_apis_secret_v0alpha1_KeeperList(ref),
|
||||
"github.com/grafana/grafana/pkg/apis/secret/v0alpha1.KeeperSpec": schema_pkg_apis_secret_v0alpha1_KeeperSpec(ref),
|
||||
@@ -345,49 +344,6 @@ func schema_pkg_apis_secret_v0alpha1_HashiCorpKeeperConfig(ref common.ReferenceC
|
||||
}
|
||||
}
|
||||
|
||||
func schema_pkg_apis_secret_v0alpha1_InlineSecureValue(ref common.ReferenceCallback) common.OpenAPIDefinition {
|
||||
return common.OpenAPIDefinition{
|
||||
Schema: spec.Schema{
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "Access secure values inside any resource",
|
||||
Type: []string{"object"},
|
||||
Properties: map[string]spec.Schema{
|
||||
"create": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "Create a secure value -- this is only used for POST/PUT",
|
||||
MinLength: ptr.To[int64](1),
|
||||
MaxLength: ptr.To[int64](24576),
|
||||
Type: []string{"string"},
|
||||
Format: "",
|
||||
},
|
||||
},
|
||||
"name": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "Name in the secret service (reference)",
|
||||
Type: []string{"string"},
|
||||
Format: "",
|
||||
},
|
||||
},
|
||||
"shared": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "The secret is shared (enterprise only)",
|
||||
Type: []string{"boolean"},
|
||||
Format: "",
|
||||
},
|
||||
},
|
||||
"remove": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "Remove this value -- cascading delete to the secret service if necessary",
|
||||
Type: []string{"boolean"},
|
||||
Format: "",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func schema_pkg_apis_secret_v0alpha1_Keeper(ref common.ReferenceCallback) common.OpenAPIDefinition {
|
||||
return common.OpenAPIDefinition{
|
||||
Schema: spec.Schema{
|
||||
|
||||
@@ -10,9 +10,9 @@ import (
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
||||
"github.com/grafana/authlib/types"
|
||||
common "github.com/grafana/grafana/pkg/apimachinery/apis/common/v0alpha1"
|
||||
"github.com/grafana/grafana/pkg/apimachinery/utils"
|
||||
datasourceV0 "github.com/grafana/grafana/pkg/apis/datasource/v0alpha1"
|
||||
secretV0 "github.com/grafana/grafana/pkg/apis/secret/v0alpha1"
|
||||
"github.com/grafana/grafana/pkg/components/simplejson"
|
||||
"github.com/grafana/grafana/pkg/services/apiserver/endpoints/request"
|
||||
gapiutil "github.com/grafana/grafana/pkg/services/apiserver/utils"
|
||||
@@ -64,7 +64,7 @@ func (r *converter) asDataSource(ds *datasources.DataSource) (*datasourceV0.Data
|
||||
}
|
||||
|
||||
if ds.SecureJsonData != nil {
|
||||
cfg.Secure = make(secretV0.InlineSecureValues)
|
||||
cfg.Secure = make(common.InlineSecureValues)
|
||||
for k := range ds.SecureJsonData {
|
||||
h := sha256.New()
|
||||
h.Write([]byte(ds.Type)) // group+resource
|
||||
@@ -73,7 +73,7 @@ func (r *converter) asDataSource(ds *datasources.DataSource) (*datasourceV0.Data
|
||||
h.Write([]byte("|"))
|
||||
h.Write([]byte(k)) // property
|
||||
n := hex.EncodeToString(h.Sum(nil))
|
||||
cfg.Secure[k] = secretV0.InlineSecureValue{
|
||||
cfg.Secure[k] = common.InlineSecureValue{
|
||||
Name: "@" + n[0:10], // ??????
|
||||
}
|
||||
}
|
||||
@@ -159,9 +159,6 @@ func toSecureJsonData(ds *datasourceV0.DataSource) (map[string]string, error) {
|
||||
|
||||
secure := map[string]string{}
|
||||
for k, v := range ds.Secure {
|
||||
if v.Shared {
|
||||
return nil, fmt.Errorf("shared secrets not yet supported (%s)", k)
|
||||
}
|
||||
if v.Create != "" {
|
||||
secure[k] = v.Create.DangerouslyExposeAndConsumeValue()
|
||||
}
|
||||
|
||||
@@ -232,5 +232,4 @@ func TestdataOpenAPIExtension() (*datasourceV0.DataSourceOpenAPIExtension, error
|
||||
oas.Routes["/test/json"] = &testcopy
|
||||
|
||||
return oas, nil
|
||||
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ import (
|
||||
"k8s.io/kube-openapi/pkg/spec3"
|
||||
"k8s.io/kube-openapi/pkg/validation/spec"
|
||||
|
||||
secretsV0 "github.com/grafana/grafana/pkg/apis/secret/v0alpha1"
|
||||
common "github.com/grafana/grafana/pkg/apimachinery/apis/common/v0alpha1"
|
||||
"github.com/grafana/grafana/pkg/registry/apis/query/queryschema"
|
||||
"github.com/grafana/grafana/pkg/services/apiserver/builder"
|
||||
)
|
||||
@@ -66,7 +66,7 @@ func (b *DataSourceAPIBuilder) PostProcessOpenAPI(oas *spec3.OpenAPI) (*spec3.Op
|
||||
}
|
||||
|
||||
if custom.SecureValues != nil {
|
||||
example := secretsV0.InlineSecureValues{}
|
||||
example := common.InlineSecureValues{}
|
||||
ref := spec.MustCreateRef("#/components/schemas/com.github.grafana.grafana.pkg.apis.secret.v0alpha1.InlineSecureValue")
|
||||
secure := &spec.Schema{
|
||||
SchemaProps: spec.SchemaProps{
|
||||
@@ -84,7 +84,7 @@ func (b *DataSourceAPIBuilder) PostProcessOpenAPI(oas *spec3.OpenAPI) (*spec3.Op
|
||||
}
|
||||
if v.Required {
|
||||
secure.Required = append(secure.Required, v.Key)
|
||||
example[v.Key] = secretsV0.InlineSecureValue{Create: "***"}
|
||||
example[v.Key] = common.InlineSecureValue{Create: "***"}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user