mirror of
https://github.com/argoproj/argo-cd
synced 2026-04-21 17:07:16 +00:00
Merge branch 'master' into fix/eks-cluster-label-version-sanitize
This commit is contained in:
commit
c34d7c0b74
81 changed files with 3085 additions and 1446 deletions
|
|
@ -145,16 +145,19 @@ linters:
|
|||
strconcat: true
|
||||
|
||||
revive:
|
||||
enable-all-rules: false
|
||||
enable-default-rules: true
|
||||
max-open-files: 2048
|
||||
# https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md
|
||||
rules:
|
||||
- name: bool-literal-in-expr
|
||||
|
||||
- name: blank-imports
|
||||
disabled: true
|
||||
|
||||
- name: bool-literal-in-expr
|
||||
|
||||
- name: context-as-argument
|
||||
arguments:
|
||||
- allowTypesBefore: '*testing.T,testing.TB'
|
||||
- allow-types-before: '*testing.T,testing.TB'
|
||||
|
||||
- name: context-keys-type
|
||||
disabled: true
|
||||
|
|
@ -166,14 +169,11 @@ linters:
|
|||
|
||||
- name: early-return
|
||||
arguments:
|
||||
- preserveScope
|
||||
- preserve-scope
|
||||
|
||||
- name: empty-block
|
||||
disabled: true
|
||||
|
||||
- name: error-naming
|
||||
disabled: true
|
||||
|
||||
- name: error-return
|
||||
|
||||
- name: error-strings
|
||||
|
|
@ -181,6 +181,9 @@ linters:
|
|||
|
||||
- name: errorf
|
||||
|
||||
- name: exported
|
||||
disabled: true
|
||||
|
||||
- name: identical-branches
|
||||
|
||||
- name: if-return
|
||||
|
|
@ -189,7 +192,7 @@ linters:
|
|||
|
||||
- name: indent-error-flow
|
||||
arguments:
|
||||
- preserveScope
|
||||
- preserve-scope
|
||||
|
||||
- name: modifies-parameter
|
||||
|
||||
|
|
@ -206,7 +209,7 @@ linters:
|
|||
|
||||
- name: superfluous-else
|
||||
arguments:
|
||||
- preserveScope
|
||||
- preserve-scope
|
||||
|
||||
- name: time-equal
|
||||
|
||||
|
|
@ -216,6 +219,8 @@ linters:
|
|||
- name: unexported-return
|
||||
disabled: true
|
||||
|
||||
- name: unnecessary-format
|
||||
|
||||
- name: unnecessary-stmt
|
||||
|
||||
- name: unreachable-code
|
||||
|
|
@ -232,8 +237,8 @@ linters:
|
|||
arguments:
|
||||
- - ID
|
||||
- - VM
|
||||
- - skipPackageNameChecks: true
|
||||
upperCaseConst: true
|
||||
- - skip-initialism-name-checks: true
|
||||
upper-case-const: true
|
||||
|
||||
staticcheck:
|
||||
checks:
|
||||
|
|
@ -255,7 +260,4 @@ linters:
|
|||
usetesting:
|
||||
os-mkdir-temp: false
|
||||
|
||||
output:
|
||||
show-stats: false
|
||||
|
||||
version: "2"
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
FROM node:20
|
||||
FROM node:24.14.1@sha256:80fc934952c8f1b2b4d39907af7211f8a9fff1a4c2cf673fb49099292c251cec
|
||||
|
||||
WORKDIR /app/ui
|
||||
|
||||
|
|
|
|||
80
assets/swagger.json
generated
80
assets/swagger.json
generated
|
|
@ -4039,6 +4039,30 @@
|
|||
"description": "Whether https should be disabled for an OCI repo.",
|
||||
"name": "insecureOciForceHttp",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Azure Service Principal Client ID.",
|
||||
"name": "azureServicePrincipalClientId",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Azure Service Principal Client Secret.",
|
||||
"name": "azureServicePrincipalClientSecret",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Azure Service Principal Tenant ID.",
|
||||
"name": "azureServicePrincipalTenantId",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Azure Active Directory Endpoint.",
|
||||
"name": "azureActiveDirectoryEndpoint",
|
||||
"in": "query"
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
|
|
@ -4946,6 +4970,30 @@
|
|||
"description": "Whether https should be disabled for an OCI repo.",
|
||||
"name": "insecureOciForceHttp",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Azure Service Principal Client ID.",
|
||||
"name": "azureServicePrincipalClientId",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Azure Service Principal Client Secret.",
|
||||
"name": "azureServicePrincipalClientSecret",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Azure Service Principal Tenant ID.",
|
||||
"name": "azureServicePrincipalTenantId",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Azure Active Directory Endpoint.",
|
||||
"name": "azureActiveDirectoryEndpoint",
|
||||
"in": "query"
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
|
|
@ -9519,6 +9567,22 @@
|
|||
"type": "object",
|
||||
"title": "RepoCreds holds the definition for repository credentials",
|
||||
"properties": {
|
||||
"azureActiveDirectoryEndpoint": {
|
||||
"type": "string",
|
||||
"title": "AzureActiveDirectoryEndpoint specifies the Azure Active Directory endpoint used for Service Principal authentication. If empty will default to https://login.microsoftonline.com"
|
||||
},
|
||||
"azureServicePrincipalClientId": {
|
||||
"type": "string",
|
||||
"title": "AzureServicePrincipalClientId specifies the client ID of the Azure Service Principal used to access the repo"
|
||||
},
|
||||
"azureServicePrincipalClientSecret": {
|
||||
"type": "string",
|
||||
"title": "AzureServicePrincipalClientSecret specifies the client secret of the Azure Service Principal used to access the repo"
|
||||
},
|
||||
"azureServicePrincipalTenantId": {
|
||||
"type": "string",
|
||||
"title": "AzureServicePrincipalTenantId specifies the tenant ID of the Azure Service Principal used to access the repo"
|
||||
},
|
||||
"bearerToken": {
|
||||
"type": "string",
|
||||
"title": "BearerToken contains the bearer token used for Git BitBucket Data Center auth at the repo server"
|
||||
|
|
@ -9618,6 +9682,22 @@
|
|||
"type": "object",
|
||||
"title": "Repository is a repository holding application configurations",
|
||||
"properties": {
|
||||
"azureActiveDirectoryEndpoint": {
|
||||
"type": "string",
|
||||
"title": "AzureActiveDirectoryEndpoint specifies the Azure Active Directory endpoint used for Service Principal authentication. If empty will default to https://login.microsoftonline.com"
|
||||
},
|
||||
"azureServicePrincipalClientId": {
|
||||
"type": "string",
|
||||
"title": "AzureServicePrincipalClientId specifies the client ID of the Azure Service Principal used to access the repo"
|
||||
},
|
||||
"azureServicePrincipalClientSecret": {
|
||||
"type": "string",
|
||||
"title": "AzureServicePrincipalClientSecret specifies the client secret of the Azure Service Principal used to access the repo"
|
||||
},
|
||||
"azureServicePrincipalTenantId": {
|
||||
"type": "string",
|
||||
"title": "AzureServicePrincipalTenantId specifies the tenant ID of the Azure Service Principal used to access the repo"
|
||||
},
|
||||
"bearerToken": {
|
||||
"type": "string",
|
||||
"title": "BearerToken contains the bearer token used for Git BitBucket Data Center auth at the repo server"
|
||||
|
|
|
|||
|
|
@ -127,7 +127,7 @@ has appropriate RBAC permissions to change other accounts.
|
|||
|
||||
_, err := usrIf.UpdatePassword(ctx, &updatePasswordRequest)
|
||||
errors.CheckError(err)
|
||||
fmt.Printf("Password updated\n")
|
||||
fmt.Print("Password updated\n")
|
||||
|
||||
if account == "" || account == userInfo.Username {
|
||||
// Get a new JWT token after updating the password
|
||||
|
|
@ -254,7 +254,7 @@ func printAccountNames(accounts []*accountpkg.Account) {
|
|||
|
||||
func printAccountsTable(items []*accountpkg.Account) {
|
||||
w := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0)
|
||||
fmt.Fprintf(w, "NAME\tENABLED\tCAPABILITIES\n")
|
||||
fmt.Fprint(w, "NAME\tENABLED\tCAPABILITIES\n")
|
||||
for _, a := range items {
|
||||
fmt.Fprintf(w, "%s\t%v\t%s\n", a.Name, a.Enabled, strings.Join(a.Capabilities, ", "))
|
||||
}
|
||||
|
|
@ -356,7 +356,7 @@ func printAccountDetails(acc *accountpkg.Account) {
|
|||
fmt.Println("NONE")
|
||||
} else {
|
||||
w := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0)
|
||||
fmt.Fprintf(w, "ID\tISSUED AT\tEXPIRING AT\n")
|
||||
fmt.Fprint(w, "ID\tISSUED AT\tEXPIRING AT\n")
|
||||
for _, t := range acc.Tokens {
|
||||
expiresAtFormatted := "never"
|
||||
if t.ExpiresAt > 0 {
|
||||
|
|
|
|||
|
|
@ -240,7 +240,7 @@ func printStatsSummary(clusters []ClusterWithInfo) {
|
|||
|
||||
avgResourcesByShard := totalResourcesCount / int64(len(resourcesCountByShard))
|
||||
w := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0)
|
||||
_, _ = fmt.Fprintf(w, "SHARD\tRESOURCES COUNT\n")
|
||||
_, _ = fmt.Fprint(w, "SHARD\tRESOURCES COUNT\n")
|
||||
for shard := 0; shard < len(resourcesCountByShard); shard++ {
|
||||
cnt := resourcesCountByShard[shard]
|
||||
percent := (float64(cnt) / float64(avgResourcesByShard)) * 100.0
|
||||
|
|
@ -318,7 +318,7 @@ func NewClusterNamespacesCommand() *cobra.Command {
|
|||
|
||||
err := runClusterNamespacesCommand(ctx, clientConfig, func(_ *versioned.Clientset, _ db.ArgoDB, clusters map[string][]string) error {
|
||||
w := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0)
|
||||
_, _ = fmt.Fprintf(w, "CLUSTER\tNAMESPACES\n")
|
||||
_, _ = fmt.Fprint(w, "CLUSTER\tNAMESPACES\n")
|
||||
|
||||
for cluster, namespaces := range clusters {
|
||||
// print shortest namespace names first
|
||||
|
|
@ -495,7 +495,7 @@ argocd admin cluster stats target-cluster`,
|
|||
errors.CheckError(err)
|
||||
|
||||
w := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0)
|
||||
_, _ = fmt.Fprintf(w, "SERVER\tSHARD\tCONNECTION\tNAMESPACES COUNT\tAPPS COUNT\tRESOURCES COUNT\n")
|
||||
_, _ = fmt.Fprint(w, "SERVER\tSHARD\tCONNECTION\tNAMESPACES COUNT\tAPPS COUNT\tRESOURCES COUNT\n")
|
||||
for _, cluster := range clusters {
|
||||
_, _ = fmt.Fprintf(w, "%s\t%d\t%s\t%d\t%d\t%d\n", cluster.Server, cluster.Shard, cluster.Info.ConnectionState.Status, len(cluster.Namespaces), cluster.Info.ApplicationsCount, cluster.Info.CacheInfo.ResourcesCount)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -313,7 +313,7 @@ argocd admin settings validate --group accounts --group plugins --load-cluster-s
|
|||
_, _ = fmt.Fprintf(os.Stdout, "%s\n", logs)
|
||||
}
|
||||
if i != len(groups)-1 {
|
||||
_, _ = fmt.Fprintf(os.Stdout, "\n")
|
||||
_, _ = fmt.Fprint(os.Stdout, "\n")
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
@ -429,7 +429,7 @@ argocd admin settings resource-overrides ignore-differences ./deploy.yaml --argo
|
|||
return
|
||||
}
|
||||
|
||||
_, _ = fmt.Printf("Following fields are ignored:\n\n")
|
||||
_, _ = fmt.Print("Following fields are ignored:\n\n")
|
||||
_ = cli.PrintDiff(res.GetName(), &res, normalizedRes)
|
||||
})
|
||||
},
|
||||
|
|
@ -476,7 +476,7 @@ argocd admin settings resource-overrides ignore-resource-updates ./deploy.yaml -
|
|||
return
|
||||
}
|
||||
|
||||
_, _ = fmt.Printf("Following fields are ignored:\n\n")
|
||||
_, _ = fmt.Print("Following fields are ignored:\n\n")
|
||||
_ = cli.PrintDiff(res.GetName(), &res, normalizedRes)
|
||||
})
|
||||
},
|
||||
|
|
@ -551,7 +551,7 @@ argocd admin settings resource-overrides action list /tmp/deploy.yaml --argocd-c
|
|||
})
|
||||
|
||||
w := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0)
|
||||
_, _ = fmt.Fprintf(w, "NAME\tDISABLED\n")
|
||||
_, _ = fmt.Fprint(w, "NAME\tDISABLED\n")
|
||||
for _, action := range availableActions {
|
||||
_, _ = fmt.Fprintf(w, "%s\t%s\n", action.Name, strconv.FormatBool(action.Disabled))
|
||||
}
|
||||
|
|
@ -622,7 +622,7 @@ argocd admin settings resource-overrides action /tmp/deploy.yaml restart --argoc
|
|||
return
|
||||
}
|
||||
|
||||
_, _ = fmt.Printf("Following fields have been changed:\n\n")
|
||||
_, _ = fmt.Print("Following fields have been changed:\n\n")
|
||||
_ = cli.PrintDiff(res.GetName(), &res, result)
|
||||
case lua.CreateOperation:
|
||||
yamlBytes, err := yaml.Marshal(impactedResource.UnstructuredObj)
|
||||
|
|
|
|||
|
|
@ -182,7 +182,7 @@ argocd admin settings rbac can someuser create application 'default/app' --defau
|
|||
// Exactly one of --namespace or --policy-file must be given.
|
||||
if (!nsOverride && policyFile == "") || (nsOverride && policyFile != "") {
|
||||
c.HelpFunc()(c, args)
|
||||
log.Fatalf("please provide exactly one of --policy-file or --namespace")
|
||||
log.Fatal("please provide exactly one of --policy-file or --namespace")
|
||||
}
|
||||
|
||||
restConfig, err := clientConfig.ClientConfig()
|
||||
|
|
@ -264,12 +264,12 @@ argocd admin settings rbac validate --namespace argocd
|
|||
|
||||
if len(args) > 0 {
|
||||
c.HelpFunc()(c, args)
|
||||
log.Fatalf("too many arguments")
|
||||
log.Fatal("too many arguments")
|
||||
}
|
||||
|
||||
if (namespace == "" && policyFile == "") || (namespace != "" && policyFile != "") {
|
||||
c.HelpFunc()(c, args)
|
||||
log.Fatalf("please provide exactly one of --policy-file or --namespace")
|
||||
log.Fatal("please provide exactly one of --policy-file or --namespace")
|
||||
}
|
||||
|
||||
restConfig, err := clientConfig.ClientConfig()
|
||||
|
|
@ -284,13 +284,13 @@ argocd admin settings rbac validate --namespace argocd
|
|||
userPolicy, _, _ := getPolicy(ctx, policyFile, realClientset, namespace)
|
||||
if userPolicy != "" {
|
||||
if err := rbac.ValidatePolicy(userPolicy); err == nil {
|
||||
fmt.Printf("Policy is valid.\n")
|
||||
fmt.Print("Policy is valid.\n")
|
||||
os.Exit(0)
|
||||
}
|
||||
fmt.Printf("Policy is invalid: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
log.Fatalf("Policy is empty or could not be loaded.")
|
||||
log.Fatal("Policy is empty or could not be loaded.")
|
||||
},
|
||||
}
|
||||
clientConfig = cli.AddKubectlFlagsToCmd(command)
|
||||
|
|
|
|||
|
|
@ -757,7 +757,7 @@ func printAppSourceDetails(appSrc *argoappv1.ApplicationSource) {
|
|||
}
|
||||
|
||||
func printAppConditions(w io.Writer, app *argoappv1.Application) {
|
||||
_, _ = fmt.Fprintf(w, "CONDITION\tMESSAGE\tLAST TRANSITION\n")
|
||||
_, _ = fmt.Fprint(w, "CONDITION\tMESSAGE\tLAST TRANSITION\n")
|
||||
for _, item := range app.Status.Conditions {
|
||||
_, _ = fmt.Fprintf(w, "%s\t%s\t%s\n", item.Type, item.Message, item.LastTransitionTime)
|
||||
}
|
||||
|
|
@ -829,7 +829,7 @@ func printHelmParams(helm *argoappv1.ApplicationSourceHelm) {
|
|||
w := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0)
|
||||
if helm != nil {
|
||||
fmt.Println()
|
||||
_, _ = fmt.Fprintf(w, "NAME\tVALUE\n")
|
||||
_, _ = fmt.Fprint(w, "NAME\tVALUE\n")
|
||||
for _, p := range helm.Parameters {
|
||||
_, _ = fmt.Fprintf(w, "%s\t%s\n", p.Name, truncateString(p.Value, paramLenLimit))
|
||||
}
|
||||
|
|
@ -1365,7 +1365,7 @@ func NewApplicationDiffCommand(clientOpts *argocdclient.ClientOptions) *cobra.Co
|
|||
serverSideDiff = hasServerSideDiffAnnotation
|
||||
} else if serverSideDiff && !hasServerSideDiffAnnotation {
|
||||
// Flag explicitly set to true, but app annotation is not set
|
||||
fmt.Fprintf(os.Stderr, "Warning: Application does not have ServerSideDiff=true annotation.\n")
|
||||
fmt.Fprint(os.Stderr, "Warning: Application does not have ServerSideDiff=true annotation.\n")
|
||||
}
|
||||
|
||||
// Server side diff with local requires server side generate to be set as there will be a mismatch with client-generated manifests.
|
||||
|
|
@ -1418,7 +1418,7 @@ func NewApplicationDiffCommand(clientOpts *argocdclient.ClientOptions) *cobra.Co
|
|||
|
||||
diffOption.serversideRes = res
|
||||
} else {
|
||||
fmt.Fprintf(os.Stderr, "Warning: local diff without --server-side-generate is deprecated and does not work with plugins. Server-side generation will be the default in v2.7.")
|
||||
fmt.Fprint(os.Stderr, "Warning: local diff without --server-side-generate is deprecated and does not work with plugins. Server-side generation will be the default in v2.7.")
|
||||
conn, clusterIf := clientset.NewClusterClientOrDie()
|
||||
defer utilio.Close(conn)
|
||||
cluster, err := clusterIf.Get(ctx, &clusterpkg.ClusterQuery{Name: app.Spec.Destination.Name, Server: app.Spec.Destination.Server})
|
||||
|
|
@ -2104,7 +2104,7 @@ func NewApplicationWaitCommand(clientOpts *argocdclient.ClientOptions) *cobra.Co
|
|||
|
||||
// printAppResources prints the resources of an application in a tabwriter table
|
||||
func printAppResources(w io.Writer, app *argoappv1.Application) {
|
||||
_, _ = fmt.Fprintf(w, "GROUP\tKIND\tNAMESPACE\tNAME\tSTATUS\tHEALTH\tHOOK\tMESSAGE\n")
|
||||
_, _ = fmt.Fprint(w, "GROUP\tKIND\tNAMESPACE\tNAME\tSTATUS\tHEALTH\tHOOK\tMESSAGE\n")
|
||||
for _, res := range getResourceStates(app, nil) {
|
||||
_, _ = fmt.Fprintf(w, "%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\n", res.Group, res.Kind, res.Namespace, res.Name, res.Status, res.Health, res.Hook, res.Message)
|
||||
}
|
||||
|
|
@ -2112,7 +2112,7 @@ func printAppResources(w io.Writer, app *argoappv1.Application) {
|
|||
|
||||
func printTreeView(nodeMapping map[string]argoappv1.ResourceNode, parentChildMapping map[string][]string, parentNodes map[string]struct{}, mapNodeNameToResourceState map[string]*resourceState) {
|
||||
w := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0)
|
||||
_, _ = fmt.Fprintf(w, "KIND/NAME\tSTATUS\tHEALTH\tMESSAGE\n")
|
||||
_, _ = fmt.Fprint(w, "KIND/NAME\tSTATUS\tHEALTH\tMESSAGE\n")
|
||||
for uid := range parentNodes {
|
||||
treeViewAppGet("", nodeMapping, parentChildMapping, nodeMapping[uid], mapNodeNameToResourceState, w)
|
||||
}
|
||||
|
|
@ -2121,7 +2121,7 @@ func printTreeView(nodeMapping map[string]argoappv1.ResourceNode, parentChildMap
|
|||
|
||||
func printTreeViewDetailed(nodeMapping map[string]argoappv1.ResourceNode, parentChildMapping map[string][]string, parentNodes map[string]struct{}, mapNodeNameToResourceState map[string]*resourceState) {
|
||||
w := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0)
|
||||
fmt.Fprintf(w, "KIND/NAME\tSTATUS\tHEALTH\tAGE\tMESSAGE\tREASON\n")
|
||||
fmt.Fprint(w, "KIND/NAME\tSTATUS\tHEALTH\tAGE\tMESSAGE\tREASON\n")
|
||||
for uid := range parentNodes {
|
||||
detailedTreeViewAppGet("", nodeMapping, parentChildMapping, nodeMapping[uid], mapNodeNameToResourceState, w)
|
||||
}
|
||||
|
|
@ -2453,7 +2453,7 @@ func NewApplicationSyncCommand(clientOpts *argocdclient.ClientOptions) *cobra.Co
|
|||
|
||||
foundDiffs = findAndPrintDiff(ctx, app, proj.Project, resources, argoSettings, diffOption, ignoreNormalizerOpts, serverSideDiff, appIf, appName, appNs, serverSideDiffConcurrency, serverSideDiffMaxBatchKB)
|
||||
if !foundDiffs {
|
||||
fmt.Printf("====== No Differences found ======\n")
|
||||
fmt.Print("====== No Differences found ======\n")
|
||||
// if no differences found, then no need to sync
|
||||
return
|
||||
}
|
||||
|
|
@ -2973,7 +2973,7 @@ func setParameterOverrides(app *argoappv1.Application, parameters []string, sour
|
|||
source.Helm.AddParameter(*newParam)
|
||||
}
|
||||
default:
|
||||
log.Fatalf("Parameters can only be set against Helm applications")
|
||||
log.Fatal("Parameters can only be set against Helm applications")
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -3028,13 +3028,13 @@ func printApplicationHistoryTable(revHistory []argoappv1.RevisionHistory) {
|
|||
}
|
||||
for i, key := range varHistoryKeys {
|
||||
_, _ = fmt.Fprintf(w, "SOURCE\t%s\n", key)
|
||||
_, _ = fmt.Fprintf(w, "ID\tDATE\tREVISION\n")
|
||||
_, _ = fmt.Fprint(w, "ID\tDATE\tREVISION\n")
|
||||
for _, history := range varHistory[key] {
|
||||
_, _ = fmt.Fprintf(w, "%d\t%s\t%s\n", history.id, history.date, history.revision)
|
||||
}
|
||||
// Add a newline if it's not the last iteration
|
||||
if i < len(varHistoryKeys)-1 {
|
||||
_, _ = fmt.Fprintf(w, "\n")
|
||||
_, _ = fmt.Fprint(w, "\n")
|
||||
}
|
||||
}
|
||||
_ = w.Flush()
|
||||
|
|
|
|||
|
|
@ -124,7 +124,7 @@ func NewApplicationResourceActionsListCommand(clientOpts *argocdclient.ClientOpt
|
|||
fmt.Println(string(jsonBytes))
|
||||
case "":
|
||||
w := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0)
|
||||
fmt.Fprintf(w, "GROUP\tKIND\tNAME\tACTION\tDISABLED\n")
|
||||
fmt.Fprint(w, "GROUP\tKIND\tNAME\tACTION\tDISABLED\n")
|
||||
for _, action := range availableActions {
|
||||
fmt.Fprintf(w, "%s\t%s\t%s\t%s\t%s\n", action.Group, action.Kind, action.Name, action.Action, strconv.FormatBool(action.Disabled))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -217,9 +217,9 @@ func reconstructObject(extracted []any, fields []string, depth int) map[string]a
|
|||
func printManifests(objs *[]unstructured.Unstructured, filteredFields bool, showName bool, output string) {
|
||||
w := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0)
|
||||
if showName {
|
||||
fmt.Fprintf(w, "FIELD\tRESOURCE NAME\tVALUE\n")
|
||||
fmt.Fprint(w, "FIELD\tRESOURCE NAME\tVALUE\n")
|
||||
} else {
|
||||
fmt.Fprintf(w, "FIELD\tVALUE\n")
|
||||
fmt.Fprint(w, "FIELD\tVALUE\n")
|
||||
}
|
||||
|
||||
for i, o := range *objs {
|
||||
|
|
@ -479,7 +479,7 @@ func printResources(listAll bool, orphaned bool, appResourceTree *v1alpha1.Appli
|
|||
w := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0)
|
||||
switch output {
|
||||
case "tree=detailed":
|
||||
fmt.Fprintf(w, "GROUP\tKIND\tNAMESPACE\tNAME\tORPHANED\tAGE\tHEALTH\tREASON\n")
|
||||
fmt.Fprint(w, "GROUP\tKIND\tNAMESPACE\tNAME\tORPHANED\tAGE\tHEALTH\tREASON\n")
|
||||
|
||||
if !orphaned || listAll {
|
||||
mapUIDToNode, mapParentToChild, parentNode := parentChildInfo(appResourceTree.Nodes)
|
||||
|
|
@ -491,7 +491,7 @@ func printResources(listAll bool, orphaned bool, appResourceTree *v1alpha1.Appli
|
|||
printDetailedTreeViewAppResourcesOrphaned(mapUIDToNode, mapParentToChild, parentNode, w)
|
||||
}
|
||||
case "tree":
|
||||
fmt.Fprintf(w, "GROUP\tKIND\tNAMESPACE\tNAME\tORPHANED\n")
|
||||
fmt.Fprint(w, "GROUP\tKIND\tNAMESPACE\tNAME\tORPHANED\n")
|
||||
|
||||
if !orphaned || listAll {
|
||||
mapUIDToNode, mapParentToChild, parentNode := parentChildInfo(appResourceTree.Nodes)
|
||||
|
|
|
|||
|
|
@ -162,7 +162,7 @@ func NewApplicationSetCreateCommand(clientOpts *argocdclient.ClientOptions) *cob
|
|||
errors.CheckError(err)
|
||||
|
||||
if len(appsets) == 0 {
|
||||
fmt.Printf("No ApplicationSets found while parsing the input file")
|
||||
fmt.Print("No ApplicationSets found while parsing the input file")
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
|
|
@ -271,7 +271,7 @@ func NewApplicationSetGenerateCommand(clientOpts *argocdclient.ClientOptions) *c
|
|||
errors.CheckError(err)
|
||||
|
||||
if len(appsets) != 1 {
|
||||
fmt.Printf("Input file must contain one ApplicationSet")
|
||||
fmt.Print("Input file must contain one ApplicationSet")
|
||||
os.Exit(1)
|
||||
}
|
||||
appset := appsets[0]
|
||||
|
|
@ -544,7 +544,7 @@ func printAppSetSummaryTable(appSet *arogappsetv1.ApplicationSet) {
|
|||
}
|
||||
|
||||
func printAppSetConditions(w io.Writer, appSet *arogappsetv1.ApplicationSet) {
|
||||
_, _ = fmt.Fprintf(w, "CONDITION\tSTATUS\tMESSAGE\tLAST TRANSITION\n")
|
||||
_, _ = fmt.Fprint(w, "CONDITION\tSTATUS\tMESSAGE\tLAST TRANSITION\n")
|
||||
for _, item := range appSet.Status.Conditions {
|
||||
_, _ = fmt.Fprintf(w, "%s\t%s\t%s\t%s\n", item.Type, item.Status, item.Message, item.LastTransitionTime)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -352,7 +352,7 @@ func NewCertListCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command {
|
|||
// Print table of certificate info
|
||||
func printCertTable(certs []appsv1.RepositoryCertificate, sortOrder string) {
|
||||
w := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0)
|
||||
fmt.Fprintf(w, "HOSTNAME\tTYPE\tSUBTYPE\tINFO\n")
|
||||
fmt.Fprint(w, "HOSTNAME\tTYPE\tSUBTYPE\tINFO\n")
|
||||
|
||||
switch sortOrder {
|
||||
case "hostname", "":
|
||||
|
|
|
|||
|
|
@ -377,15 +377,15 @@ func formatNamespaces(cluster argoappv1.Cluster) string {
|
|||
|
||||
func printClusterDetails(clusters []argoappv1.Cluster) {
|
||||
for _, cluster := range clusters {
|
||||
fmt.Printf("Cluster information\n\n")
|
||||
fmt.Print("Cluster information\n\n")
|
||||
fmt.Printf(" Server URL: %s\n", cluster.Server)
|
||||
fmt.Printf(" Server Name: %s\n", strWithDefault(cluster.Name, "-"))
|
||||
fmt.Printf(" Server Version: %s\n", cluster.Info.ServerVersion)
|
||||
fmt.Printf(" Namespaces: %s\n", formatNamespaces(cluster))
|
||||
fmt.Printf("\nTLS configuration\n\n")
|
||||
fmt.Print("\nTLS configuration\n\n")
|
||||
fmt.Printf(" Client cert: %v\n", len(cluster.Config.CertData) != 0)
|
||||
fmt.Printf(" Cert validation: %v\n", !cluster.Config.Insecure)
|
||||
fmt.Printf("\nAuthentication\n\n")
|
||||
fmt.Print("\nAuthentication\n\n")
|
||||
fmt.Printf(" Basic authentication: %v\n", cluster.Config.Username != "")
|
||||
fmt.Printf(" oAuth authentication: %v\n", cluster.Config.BearerToken != "")
|
||||
fmt.Printf(" AWS authentication: %v\n", cluster.Config.AWSAuthConfig != nil)
|
||||
|
|
@ -468,7 +468,7 @@ argocd cluster rm cluster-name`,
|
|||
// Print table of cluster information
|
||||
func printClusterTable(clusters []argoappv1.Cluster) {
|
||||
w := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0)
|
||||
_, _ = fmt.Fprintf(w, "SERVER\tNAME\tVERSION\tSTATUS\tMESSAGE\tPROJECT\n")
|
||||
_, _ = fmt.Fprint(w, "SERVER\tNAME\tVERSION\tSTATUS\tMESSAGE\tPROJECT\n")
|
||||
for _, c := range clusters {
|
||||
server := c.Server
|
||||
if len(c.Namespaces) > 0 {
|
||||
|
|
|
|||
|
|
@ -151,7 +151,7 @@ func NewGPGAddCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command {
|
|||
if len(resp.Skipped) > 0 {
|
||||
fmt.Printf(", and %d key(s) were skipped because they exist already", len(resp.Skipped))
|
||||
}
|
||||
fmt.Printf(".\n")
|
||||
fmt.Print(".\n")
|
||||
},
|
||||
}
|
||||
command.Flags().StringVarP(&fromFile, "from", "f", "", "Path to the file that contains the GPG public key to import")
|
||||
|
|
@ -192,7 +192,7 @@ func NewGPGDeleteCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command
|
|||
// Print table of certificate info
|
||||
func printKeyTable(keys []appsv1.GnuPGPublicKey) {
|
||||
w := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0)
|
||||
fmt.Fprintf(w, "KEYID\tTYPE\tIDENTITY\n")
|
||||
fmt.Fprint(w, "KEYID\tTYPE\tIDENTITY\n")
|
||||
|
||||
for _, k := range keys {
|
||||
fmt.Fprintf(w, "%s\t%s\t%s\n", k.KeyID, strings.ToUpper(k.SubType), k.Owner)
|
||||
|
|
|
|||
|
|
@ -274,7 +274,7 @@ func oauth2Login(
|
|||
// flow where the id_token is contained in a URL fragment, making it inaccessible to be
|
||||
// read from the request. This javascript will redirect the browser to send the
|
||||
// fragments as query parameters so our callback handler can read and return token.
|
||||
fmt.Fprintf(w, `<script>window.location.search = window.location.hash.substring(1)</script>`)
|
||||
fmt.Fprint(w, `<script>window.location.search = window.location.hash.substring(1)</script>`)
|
||||
return
|
||||
}
|
||||
|
||||
|
|
@ -351,7 +351,7 @@ func oauth2Login(
|
|||
if errMsg != "" {
|
||||
log.Fatal(errMsg)
|
||||
}
|
||||
fmt.Printf("Authentication successful\n")
|
||||
fmt.Print("Authentication successful\n")
|
||||
ctx, cancel := context.WithTimeout(ctx, 1*time.Second)
|
||||
defer cancel()
|
||||
_ = srv.Shutdown(ctx)
|
||||
|
|
@ -375,7 +375,7 @@ func passwordLogin(ctx context.Context, acdClient argocdclient.Client, username,
|
|||
|
||||
func ssoAuthFlow(url string, ssoLaunchBrowser bool) {
|
||||
if ssoLaunchBrowser {
|
||||
fmt.Printf("Opening system default browser for authentication\n")
|
||||
fmt.Print("Opening system default browser for authentication\n")
|
||||
err := open.Start(url)
|
||||
errors.CheckError(err)
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@ argocd logout cd.argoproj.io
|
|||
localCfg, err := localconfig.ReadLocalConfig(clientOpts.ConfigPath)
|
||||
errutil.CheckError(err)
|
||||
if localCfg == nil {
|
||||
log.Fatalf("Nothing to logout from")
|
||||
log.Fatal("Nothing to logout from")
|
||||
}
|
||||
|
||||
promptUtil := utils.NewPrompt(clientOpts.PromptsEnabled)
|
||||
|
|
|
|||
|
|
@ -493,7 +493,7 @@ func NewProjectAddSourceCommand(clientOpts *argocdclient.ClientOptions) *cobra.C
|
|||
|
||||
for _, item := range proj.Spec.SourceRepos {
|
||||
if item == "*" {
|
||||
fmt.Printf("Source repository '*' already allowed in project\n")
|
||||
fmt.Print("Source repository '*' already allowed in project\n")
|
||||
return
|
||||
}
|
||||
if git.SameURL(item, url) {
|
||||
|
|
@ -535,7 +535,7 @@ func NewProjectAddSourceNamespace(clientOpts *argocdclient.ClientOptions) *cobra
|
|||
|
||||
for _, item := range proj.Spec.SourceNamespaces {
|
||||
if item == "*" || item == srcNamespace {
|
||||
fmt.Printf("Source namespace '*' already allowed in project\n")
|
||||
fmt.Print("Source namespace '*' already allowed in project\n")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
|
@ -868,7 +868,7 @@ func printProjectNames(projects []v1alpha1.AppProject) {
|
|||
// Print table of project info
|
||||
func printProjectTable(projects []v1alpha1.AppProject) {
|
||||
w := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0)
|
||||
fmt.Fprintf(w, "NAME\tDESCRIPTION\tDESTINATIONS\tSOURCES\tCLUSTER-RESOURCE-WHITELIST\tNAMESPACE-RESOURCE-BLACKLIST\tSIGNATURE-KEYS\tORPHANED-RESOURCES\tDESTINATION-SERVICE-ACCOUNTS\n")
|
||||
fmt.Fprint(w, "NAME\tDESCRIPTION\tDESTINATIONS\tSOURCES\tCLUSTER-RESOURCE-WHITELIST\tNAMESPACE-RESOURCE-BLACKLIST\tSIGNATURE-KEYS\tORPHANED-RESOURCES\tDESTINATION-SERVICE-ACCOUNTS\n")
|
||||
for _, p := range projects {
|
||||
printProjectLine(w, &p)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -421,7 +421,7 @@ fa9d3517-c52d-434c-9bff-215b38508842 2023-10-08T11:08:18+01:00 Never
|
|||
}
|
||||
|
||||
writer := tabwriter.NewWriter(os.Stdout, 0, 0, 4, ' ', 0)
|
||||
_, err = fmt.Fprintf(writer, "ID\tISSUED AT\tEXPIRES AT\n")
|
||||
_, err = fmt.Fprint(writer, "ID\tISSUED AT\tEXPIRES AT\n")
|
||||
errors.CheckError(err)
|
||||
|
||||
tokenRowFormat := "%s\t%v\t%v\n"
|
||||
|
|
@ -515,7 +515,7 @@ func printProjectRoleListName(roles []v1alpha1.ProjectRole) {
|
|||
// Print table of project roles
|
||||
func printProjectRoleListTable(roles []v1alpha1.ProjectRole) {
|
||||
w := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0)
|
||||
fmt.Fprintf(w, "ROLE-NAME\tDESCRIPTION\n")
|
||||
fmt.Fprint(w, "ROLE-NAME\tDESCRIPTION\n")
|
||||
for _, role := range roles {
|
||||
fmt.Fprintf(w, "%s\t%s\n", role.Name, role.Description)
|
||||
}
|
||||
|
|
@ -603,9 +603,9 @@ ID ISSUED-AT EXPIRES-AT
|
|||
printRoleFmtStr := "%-15s%s\n"
|
||||
fmt.Printf(printRoleFmtStr, "Role Name:", roleName)
|
||||
fmt.Printf(printRoleFmtStr, "Description:", role.Description)
|
||||
fmt.Printf("Policies:\n")
|
||||
fmt.Print("Policies:\n")
|
||||
fmt.Printf("%s\n", proj.ProjectPoliciesString())
|
||||
fmt.Printf("Groups:\n")
|
||||
fmt.Print("Groups:\n")
|
||||
// if the group exists in the role
|
||||
// range over each group and print it
|
||||
if v1alpha1.RoleGroupExists(role) {
|
||||
|
|
@ -615,9 +615,9 @@ ID ISSUED-AT EXPIRES-AT
|
|||
} else {
|
||||
fmt.Println("<none>")
|
||||
}
|
||||
fmt.Printf("JWT Tokens:\n")
|
||||
fmt.Print("JWT Tokens:\n")
|
||||
w := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0)
|
||||
fmt.Fprintf(w, "ID\tISSUED-AT\tEXPIRES-AT\n")
|
||||
fmt.Fprint(w, "ID\tISSUED-AT\tEXPIRES-AT\n")
|
||||
for _, token := range proj.Status.JWTTokensByRole[roleName].Items {
|
||||
expiresAt := "<none>"
|
||||
if token.ExpiresAt > 0 {
|
||||
|
|
|
|||
|
|
@ -248,7 +248,7 @@ argocd proj windows delete new-project 1`,
|
|||
_, err = projIf.Update(ctx, &projectpkg.ProjectUpdateRequest{Project: proj})
|
||||
errors.CheckError(err)
|
||||
} else {
|
||||
fmt.Printf("The command to delete the sync window was cancelled\n")
|
||||
fmt.Print("The command to delete the sync window was cancelled\n")
|
||||
}
|
||||
},
|
||||
}
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ func NewReloginCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command {
|
|||
localCfg, err := localconfig.ReadLocalConfig(clientOpts.ConfigPath)
|
||||
errors.CheckError(err)
|
||||
if localCfg == nil {
|
||||
log.Fatalf("No context found. Login using `argocd login`")
|
||||
log.Fatal("No context found. Login using `argocd login`")
|
||||
}
|
||||
configCtx, err := localCfg.ResolveContext(localCfg.CurrentContext)
|
||||
errors.CheckError(err)
|
||||
|
|
|
|||
|
|
@ -102,6 +102,12 @@ func NewRepoAddCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command {
|
|||
|
||||
# Add a private Git repository on Google Cloud Sources via GCP service account credentials
|
||||
argocd repo add https://source.developers.google.com/p/my-google-cloud-project/r/my-repo --gcp-service-account-key-path service-account-key.json
|
||||
|
||||
# Add a private Git repository on Azure Devops via Azure Service Principal credentials
|
||||
argocd repo add https://dev.azure.com/my-devops-organization/my-devops-project/_git/my-devops-repo --azure-service-principal-client-id 12345678-1234-1234-1234-123456789012 --azure-service-principal-client-secret test --azure-service-principal-tenant-id 12345678-1234-1234-1234-123456789012
|
||||
|
||||
# Add a private Git repository on Azure Devops via Azure Service Principal credentials when not using default Azure public cloud
|
||||
argocd repo add https://dev.azure.com/my-devops-organization/my-devops-project/_git/my-devops-repo --azure-service-principal-client-id 12345678-1234-1234-1234-123456789012 --azure-service-principal-client-secret test --azure-service-principal-tenant-id 12345678-1234-1234-1234-123456789012 --azure-active-directory-endpoint https://login.microsoftonline.de
|
||||
`
|
||||
|
||||
command := &cobra.Command{
|
||||
|
|
@ -191,6 +197,10 @@ func NewRepoAddCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command {
|
|||
repoOpts.Repo.NoProxy = repoOpts.NoProxy
|
||||
repoOpts.Repo.ForceHttpBasicAuth = repoOpts.ForceHttpBasicAuth
|
||||
repoOpts.Repo.UseAzureWorkloadIdentity = repoOpts.UseAzureWorkloadIdentity
|
||||
repoOpts.Repo.AzureServicePrincipalTenantId = repoOpts.AzureServicePrincipalTenantId
|
||||
repoOpts.Repo.AzureServicePrincipalClientId = repoOpts.AzureServicePrincipalClientId
|
||||
repoOpts.Repo.AzureServicePrincipalClientSecret = repoOpts.AzureServicePrincipalClientSecret
|
||||
repoOpts.Repo.AzureActiveDirectoryEndpoint = repoOpts.AzureActiveDirectoryEndpoint
|
||||
repoOpts.Repo.Depth = repoOpts.Depth
|
||||
repoOpts.Repo.WebhookManifestCacheWarmDisabled = repoOpts.WebhookManifestCacheWarmDisabled
|
||||
|
||||
|
|
@ -226,27 +236,31 @@ func NewRepoAddCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command {
|
|||
// are high that we do not have the given URL pointing to a valid Git
|
||||
// repo anyway.
|
||||
repoAccessReq := repositorypkg.RepoAccessQuery{
|
||||
Repo: repoOpts.Repo.Repo,
|
||||
Type: repoOpts.Repo.Type,
|
||||
Name: repoOpts.Repo.Name,
|
||||
Username: repoOpts.Repo.Username,
|
||||
Password: repoOpts.Repo.Password,
|
||||
BearerToken: repoOpts.Repo.BearerToken,
|
||||
SshPrivateKey: repoOpts.Repo.SSHPrivateKey,
|
||||
TlsClientCertData: repoOpts.Repo.TLSClientCertData,
|
||||
TlsClientCertKey: repoOpts.Repo.TLSClientCertKey,
|
||||
Insecure: repoOpts.Repo.IsInsecure(),
|
||||
EnableOci: repoOpts.Repo.EnableOCI,
|
||||
GithubAppPrivateKey: repoOpts.Repo.GithubAppPrivateKey,
|
||||
GithubAppID: repoOpts.Repo.GithubAppId,
|
||||
GithubAppInstallationID: repoOpts.Repo.GithubAppInstallationId,
|
||||
GithubAppEnterpriseBaseUrl: repoOpts.Repo.GitHubAppEnterpriseBaseURL,
|
||||
Proxy: repoOpts.Proxy,
|
||||
Project: repoOpts.Repo.Project,
|
||||
GcpServiceAccountKey: repoOpts.Repo.GCPServiceAccountKey,
|
||||
ForceHttpBasicAuth: repoOpts.Repo.ForceHttpBasicAuth,
|
||||
UseAzureWorkloadIdentity: repoOpts.Repo.UseAzureWorkloadIdentity,
|
||||
InsecureOciForceHttp: repoOpts.Repo.InsecureOCIForceHttp,
|
||||
Repo: repoOpts.Repo.Repo,
|
||||
Type: repoOpts.Repo.Type,
|
||||
Name: repoOpts.Repo.Name,
|
||||
Username: repoOpts.Repo.Username,
|
||||
Password: repoOpts.Repo.Password,
|
||||
BearerToken: repoOpts.Repo.BearerToken,
|
||||
SshPrivateKey: repoOpts.Repo.SSHPrivateKey,
|
||||
TlsClientCertData: repoOpts.Repo.TLSClientCertData,
|
||||
TlsClientCertKey: repoOpts.Repo.TLSClientCertKey,
|
||||
Insecure: repoOpts.Repo.IsInsecure(),
|
||||
EnableOci: repoOpts.Repo.EnableOCI,
|
||||
GithubAppPrivateKey: repoOpts.Repo.GithubAppPrivateKey,
|
||||
GithubAppID: repoOpts.Repo.GithubAppId,
|
||||
GithubAppInstallationID: repoOpts.Repo.GithubAppInstallationId,
|
||||
GithubAppEnterpriseBaseUrl: repoOpts.Repo.GitHubAppEnterpriseBaseURL,
|
||||
Proxy: repoOpts.Proxy,
|
||||
Project: repoOpts.Repo.Project,
|
||||
GcpServiceAccountKey: repoOpts.Repo.GCPServiceAccountKey,
|
||||
ForceHttpBasicAuth: repoOpts.Repo.ForceHttpBasicAuth,
|
||||
UseAzureWorkloadIdentity: repoOpts.Repo.UseAzureWorkloadIdentity,
|
||||
InsecureOciForceHttp: repoOpts.Repo.InsecureOCIForceHttp,
|
||||
AzureServicePrincipalTenantId: repoOpts.Repo.AzureServicePrincipalTenantId,
|
||||
AzureServicePrincipalClientId: repoOpts.Repo.AzureServicePrincipalClientId,
|
||||
AzureServicePrincipalClientSecret: repoOpts.Repo.AzureServicePrincipalClientSecret,
|
||||
AzureActiveDirectoryEndpoint: repoOpts.Repo.AzureActiveDirectoryEndpoint,
|
||||
}
|
||||
_, err = repoIf.ValidateAccess(ctx, &repoAccessReq)
|
||||
errors.CheckError(err)
|
||||
|
|
@ -315,7 +329,7 @@ func NewRepoRemoveCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command
|
|||
// Print table of repo info
|
||||
func printRepoTable(repos appsv1.Repositories) {
|
||||
w := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0)
|
||||
_, _ = fmt.Fprintf(w, "TYPE\tNAME\tREPO\tINSECURE\tOCI\tLFS\tCREDS\tSTATUS\tMESSAGE\tPROJECT\n")
|
||||
_, _ = fmt.Fprint(w, "TYPE\tNAME\tREPO\tINSECURE\tOCI\tLFS\tCREDS\tSTATUS\tMESSAGE\tPROJECT\n")
|
||||
for _, r := range repos {
|
||||
var hasCreds string
|
||||
if r.InheritedCreds {
|
||||
|
|
|
|||
|
|
@ -83,6 +83,12 @@ func NewRepoCredsAddCommand(clientOpts *argocdclient.ClientOptions) *cobra.Comma
|
|||
|
||||
# Add credentials with GCP credentials for all repositories under https://source.developers.google.com/p/my-google-cloud-project/r/
|
||||
argocd repocreds add https://source.developers.google.com/p/my-google-cloud-project/r/ --gcp-service-account-key-path service-account-key.json
|
||||
|
||||
# Add credentials with Azure Service Principal to use for all repositories under https://dev.azure.com/my-devops-organization
|
||||
argocd repocreds add https://dev.azure.com/my-devops-organization --azure-service-principal-client-id 12345678-1234-1234-1234-123456789012 --azure-service-principal-client-secret test --azure-service-principal-tenant-id 12345678-1234-1234-1234-123456789012
|
||||
|
||||
# Add credentials with Azure Service Principal to use for all repositories under https://dev.azure.com/my-devops-organization when not using default Azure public cloud
|
||||
argocd repocreds add https://dev.azure.com/my-devops-organization --azure-service-principal-client-id 12345678-1234-1234-1234-123456789012 --azure-service-principal-client-secret test --azure-service-principal-tenant-id 12345678-1234-1234-1234-123456789012 --azure-active-directory-endpoint https://login.microsoftonline.de
|
||||
`
|
||||
|
||||
command := &cobra.Command{
|
||||
|
|
@ -201,6 +207,10 @@ func NewRepoCredsAddCommand(clientOpts *argocdclient.ClientOptions) *cobra.Comma
|
|||
command.Flags().BoolVar(&repo.ForceHttpBasicAuth, "force-http-basic-auth", false, "whether to force basic auth when connecting via HTTP")
|
||||
command.Flags().BoolVar(&repo.UseAzureWorkloadIdentity, "use-azure-workload-identity", false, "whether to use azure workload identity for authentication")
|
||||
command.Flags().StringVar(&repo.Proxy, "proxy-url", "", "If provided, this URL will be used to connect via proxy")
|
||||
command.Flags().StringVar(&repo.AzureServicePrincipalClientId, "azure-service-principal-client-id", "", "client id of the Azure Service Principal")
|
||||
command.Flags().StringVar(&repo.AzureServicePrincipalClientSecret, "azure-service-principal-client-secret", "", "client secret of the Azure Service Principal")
|
||||
command.Flags().StringVar(&repo.AzureServicePrincipalTenantId, "azure-service-principal-tenant-id", "", "tenant id of the Azure Service Principal")
|
||||
command.Flags().StringVar(&repo.AzureActiveDirectoryEndpoint, "azure-active-directory-endpoint", "", "Active Directory endpoint when not using default Azure public cloud (e.g. https://login.microsoftonline.de)")
|
||||
return command
|
||||
}
|
||||
|
||||
|
|
@ -243,7 +253,7 @@ func NewRepoCredsRemoveCommand(clientOpts *argocdclient.ClientOptions) *cobra.Co
|
|||
// Print the repository credentials as table
|
||||
func printRepoCredsTable(repos []appsv1.RepoCreds) {
|
||||
w := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0)
|
||||
fmt.Fprintf(w, "URL PATTERN\tUSERNAME\tSSH_CREDS\tTLS_CREDS\n")
|
||||
fmt.Fprint(w, "URL PATTERN\tUSERNAME\tSSH_CREDS\tTLS_CREDS\n")
|
||||
for _, r := range repos {
|
||||
if r.Username == "" {
|
||||
r.Username = "-"
|
||||
|
|
|
|||
|
|
@ -541,7 +541,7 @@ func SetParameterOverrides(app *argoappv1.Application, parameters []string, inde
|
|||
source.Helm.AddParameter(*newParam)
|
||||
}
|
||||
default:
|
||||
log.Fatalf("Parameters can only be set against Helm applications")
|
||||
log.Fatal("Parameters can only be set against Helm applications")
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ func TestReadAppSet(t *testing.T) {
|
|||
var appSets []*argoprojiov1alpha1.ApplicationSet
|
||||
err := readAppset([]byte(appSet), &appSets)
|
||||
if err != nil {
|
||||
t.Logf("Failed reading appset file")
|
||||
t.Log("Failed reading appset file")
|
||||
}
|
||||
assert.Len(t, appSets, 1)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,27 +8,31 @@ import (
|
|||
)
|
||||
|
||||
type RepoOptions struct {
|
||||
Repo appsv1.Repository
|
||||
Upsert bool
|
||||
SshPrivateKeyPath string //nolint:revive //FIXME(var-naming)
|
||||
InsecureOCIForceHTTP bool
|
||||
InsecureIgnoreHostKey bool
|
||||
InsecureSkipServerVerification bool
|
||||
TlsClientCertPath string //nolint:revive //FIXME(var-naming)
|
||||
TlsClientCertKeyPath string //nolint:revive //FIXME(var-naming)
|
||||
EnableLfs bool
|
||||
EnableOci bool
|
||||
GithubAppId int64
|
||||
GithubAppInstallationId int64
|
||||
GithubAppPrivateKeyPath string
|
||||
GitHubAppEnterpriseBaseURL string
|
||||
Proxy string
|
||||
NoProxy string
|
||||
GCPServiceAccountKeyPath string
|
||||
ForceHttpBasicAuth bool //nolint:revive //FIXME(var-naming)
|
||||
UseAzureWorkloadIdentity bool
|
||||
Depth int64
|
||||
WebhookManifestCacheWarmDisabled bool
|
||||
Repo appsv1.Repository
|
||||
Upsert bool
|
||||
SshPrivateKeyPath string //nolint:revive //FIXME(var-naming)
|
||||
InsecureOCIForceHTTP bool
|
||||
InsecureIgnoreHostKey bool
|
||||
InsecureSkipServerVerification bool
|
||||
TlsClientCertPath string //nolint:revive //FIXME(var-naming)
|
||||
TlsClientCertKeyPath string //nolint:revive //FIXME(var-naming)
|
||||
EnableLfs bool
|
||||
EnableOci bool
|
||||
GithubAppId int64
|
||||
GithubAppInstallationId int64
|
||||
GithubAppPrivateKeyPath string
|
||||
GitHubAppEnterpriseBaseURL string
|
||||
Proxy string
|
||||
NoProxy string
|
||||
GCPServiceAccountKeyPath string
|
||||
ForceHttpBasicAuth bool //nolint:revive //FIXME(var-naming)
|
||||
UseAzureWorkloadIdentity bool
|
||||
Depth int64
|
||||
WebhookManifestCacheWarmDisabled bool
|
||||
AzureServicePrincipalTenantId string
|
||||
AzureServicePrincipalClientId string
|
||||
AzureServicePrincipalClientSecret string
|
||||
AzureActiveDirectoryEndpoint string
|
||||
}
|
||||
|
||||
func AddRepoFlags(command *cobra.Command, opts *RepoOptions) {
|
||||
|
|
@ -57,4 +61,8 @@ func AddRepoFlags(command *cobra.Command, opts *RepoOptions) {
|
|||
command.Flags().BoolVar(&opts.InsecureOCIForceHTTP, "insecure-oci-force-http", false, "Use http when accessing an OCI repository")
|
||||
command.Flags().Int64Var(&opts.Depth, "depth", 0, "Specify a custom depth for git clone operations. Unless specified, a full clone is performed using the depth of 0")
|
||||
command.Flags().BoolVar(&opts.WebhookManifestCacheWarmDisabled, "webhook-manifest-cache-warm-disabled", false, "disable manifest cache warming during webhook processing for this repository (recommended for large monorepos with plain YAML manifests)")
|
||||
command.Flags().StringVar(&opts.AzureServicePrincipalTenantId, "azure-service-principal-tenant-id", "", "tenant id of the Azure Service Principal")
|
||||
command.Flags().StringVar(&opts.AzureServicePrincipalClientId, "azure-service-principal-client-id", "", "client id of the Azure Service Principal")
|
||||
command.Flags().StringVar(&opts.AzureServicePrincipalClientSecret, "azure-service-principal-client-secret", "", "client secret of the Azure Service Principal")
|
||||
command.Flags().StringVar(&opts.AzureActiveDirectoryEndpoint, "azure-active-directory-endpoint", "", "Active Directory endpoint when not using default Azure public cloud (e.g. https://login.microsoftonline.de)")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -137,6 +137,9 @@ const (
|
|||
ChangePasswordSSOTokenMaxAge = time.Minute * 5
|
||||
// GithubAppCredsExpirationDuration is the default time used to cache the GitHub app credentials
|
||||
GithubAppCredsExpirationDuration = time.Minute * 60
|
||||
// AzureServicePrincipalCredsExpirationDuration is the default time used to cache the Azure service principal credentials
|
||||
// SP tokens are valid for 60 minutes, so cache for 59 minutes to avoid issues with token expiration when taking the cleanup interval of 1 minute into account
|
||||
AzureServicePrincipalCredsExpirationDuration = time.Minute * 59
|
||||
|
||||
// PasswordPatten is the default password patten
|
||||
PasswordPatten = `^.{8,32}$`
|
||||
|
|
@ -297,6 +300,8 @@ const (
|
|||
EnvEnableGRPCTimeHistogramEnv = "ARGOCD_ENABLE_GRPC_TIME_HISTOGRAM"
|
||||
// EnvGithubAppCredsExpirationDuration controls the caching of Github app credentials. This value is in minutes (default: 60)
|
||||
EnvGithubAppCredsExpirationDuration = "ARGOCD_GITHUB_APP_CREDS_EXPIRATION_DURATION"
|
||||
// EnvAzureServicePrincipalCredsExpirationDuration controls the caching of Azure service principal credentials. This value is in minutes (default: 59). Any value greater than 59 will be set to 59 minutes
|
||||
EnvAzureServicePrincipalCredsExpirationDuration = "ARGOCD_AZURE_SERVICE_PRINCIPAL_CREDS_EXPIRATION_DURATION"
|
||||
// EnvHelmIndexCacheDuration controls how the helm repository index file is cached for (default: 0)
|
||||
EnvHelmIndexCacheDuration = "ARGOCD_HELM_INDEX_CACHE_DURATION"
|
||||
// EnvAppConfigPath allows to override the configuration path for repo server
|
||||
|
|
|
|||
|
|
@ -2345,7 +2345,7 @@ func (ctrl *ApplicationController) autoSync(app *appv1.Application, syncStatus *
|
|||
ctrl.writeBackToInformer(updatedApp)
|
||||
ts.AddCheckpoint("write_back_to_informer_ms")
|
||||
|
||||
message := fmt.Sprintf("Initiated automated sync to %s", desiredRevisions)
|
||||
message := fmt.Sprintf("Initiated automated sync to '%s'", strings.Join(desiredRevisions, ", "))
|
||||
ctrl.logAppEvent(context.TODO(), app, argo.EventInfo{Reason: argo.EventReasonOperationStarted, Type: corev1.EventTypeNormal}, message)
|
||||
logCtx.Info(message)
|
||||
return nil, setOpTime
|
||||
|
|
|
|||
|
|
@ -358,39 +358,6 @@ func (m *appStateManager) GetRepoObjs(ctx context.Context, app *v1alpha1.Applica
|
|||
return targetObjs, manifestInfos, revisionsMayHaveChanges, nil
|
||||
}
|
||||
|
||||
// ResolveGitRevision will resolve the given revision to a full commit SHA. Only works for git.
|
||||
func (m *appStateManager) ResolveGitRevision(repoURL string, revision string) (string, error) {
|
||||
conn, repoClient, err := m.repoClientset.NewRepoServerClient()
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to connect to repo server: %w", err)
|
||||
}
|
||||
defer utilio.Close(conn)
|
||||
|
||||
repo, err := m.db.GetRepository(context.Background(), repoURL, "")
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to get repo %q: %w", repoURL, err)
|
||||
}
|
||||
|
||||
// Mock the app. The repo-server only needs to know whether the "chart" field is populated.
|
||||
app := &v1alpha1.Application{
|
||||
Spec: v1alpha1.ApplicationSpec{
|
||||
Source: &v1alpha1.ApplicationSource{
|
||||
RepoURL: repoURL,
|
||||
TargetRevision: revision,
|
||||
},
|
||||
},
|
||||
}
|
||||
resp, err := repoClient.ResolveRevision(context.Background(), &apiclient.ResolveRevisionRequest{
|
||||
Repo: repo,
|
||||
App: app,
|
||||
AmbiguousRevision: revision,
|
||||
})
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to determine whether the dry source has changed: %w", err)
|
||||
}
|
||||
return resp.Revision, nil
|
||||
}
|
||||
|
||||
func unmarshalManifests(manifests []string) ([]*unstructured.Unstructured, error) {
|
||||
targetObjs := make([]*unstructured.Unstructured, 0)
|
||||
for _, manifest := range manifests {
|
||||
|
|
|
|||
BIN
docs/assets/repo-add-azure-service-principal.png
Normal file
BIN
docs/assets/repo-add-azure-service-principal.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 75 KiB |
|
|
@ -45,8 +45,8 @@ In order to enable this feature, the Argo CD administrator must reconfigure the
|
|||
The `--application-namespaces` parameter takes a comma-separated list of namespaces where `Applications` are to be allowed in. Each entry of the list supports:
|
||||
|
||||
- shell-style wildcards such as `*`, so for example the entry `app-team-*` would match `app-team-one` and `app-team-two`. To enable all namespaces on the cluster where Argo CD is running on, you can just specify `*`, i.e. `--application-namespaces=*`.
|
||||
- regex, requires wrapping the string in ```/```, example to allow all namespaces except a particular one: ```/^((?!not-allowed).)*$/```.
|
||||
|
||||
- regex, requires wrapping the string in `/`, example to allow all namespaces except a particular one: `/^((?!not-allowed).)*$/`.
|
||||
|
||||
The startup parameters for both, the `argocd-server` and the `argocd-application-controller` can also be conveniently set up and kept in sync by specifying the `application.namespaces` settings in the `argocd-cmd-params-cm` ConfigMap _instead_ of changing the manifests for the respective workloads. For example:
|
||||
|
||||
```yaml
|
||||
|
|
@ -94,7 +94,7 @@ metadata:
|
|||
namespace: argocd
|
||||
spec:
|
||||
sourceNamespaces:
|
||||
- namespace-one
|
||||
- namespace-one
|
||||
```
|
||||
|
||||
and
|
||||
|
|
@ -107,7 +107,7 @@ metadata:
|
|||
namespace: argocd
|
||||
spec:
|
||||
sourceNamespaces:
|
||||
- namespace-two
|
||||
- namespace-two
|
||||
```
|
||||
|
||||
In order for an Application to set `.spec.project` to `project-one`, it would have to be created in either namespace `namespace-one` or `argocd`. Likewise, in order for an Application to set `.spec.project` to `project-two`, it would have to be created in either namespace `namespace-two` or `argocd`.
|
||||
|
|
@ -138,7 +138,11 @@ For backwards compatibility, if the namespace of the Application is the control
|
|||
|
||||
The RBAC syntax for Application objects has been changed from `<project>/<application>` to `<project>/<namespace>/<application>` to accommodate the need to restrict access based on the source namespace of the Application to be managed.
|
||||
|
||||
For backwards compatibility, Applications in the `argocd` namespace can still be referred to as `<project>/<application>` in the RBAC policy rules.
|
||||
For backwards compatibility, Applications in the `argocd` namespace will still be referred to as `<project>/<application>` in the RBAC policy rules.
|
||||
|
||||
!!! note
|
||||
|
||||
Due to backward compatibility, it is not possible to define RBAC policies specifically for applications in the Argo CD control plane namespace (typically `argocd`) using the pattern `foo/argocd/*`. Applications in the control plane namespace are always normalized to the 2-segment format `<project>/<application>` in RBAC enforcement. For security reasons, an AppProject should never grant access to the control plane namespace through the `.spec.sourceNamespaces` field, as this would allow users to create applications with elevated privileges.
|
||||
|
||||
Wildcards do not make any distinction between project and application namespaces yet. For example, the following RBAC rule would match any application belonging to project `foo`, regardless of the namespace it is created in:
|
||||
|
||||
|
|
@ -151,7 +155,7 @@ If you want to restrict access to be granted only to `Applications` in project `
|
|||
```
|
||||
p, somerole, applications, get, foo/bar/*, allow
|
||||
```
|
||||
|
||||
|
||||
## Managing applications in other namespaces
|
||||
|
||||
### Declaratively
|
||||
|
|
@ -175,10 +179,10 @@ The project `some-project` will then need to specify `some-namespace` in the lis
|
|||
kind: AppProject
|
||||
apiVersion: argoproj.io/v1alpha1
|
||||
metadata:
|
||||
name: some-project
|
||||
namespace: argocd
|
||||
name: some-project
|
||||
namespace: argocd
|
||||
spec:
|
||||
sourceNamespaces:
|
||||
sourceNamespaces:
|
||||
- some-namespace
|
||||
```
|
||||
|
||||
|
|
|
|||
|
|
@ -205,7 +205,11 @@ For backwards compatibility, if the namespace of the ApplicationSet is the contr
|
|||
|
||||
The RBAC syntax for Application objects has been changed from `<project>/<applicationset>` to `<project>/<namespace>/<applicationset>` to accommodate the need to restrict access based on the source namespace of the Application to be managed.
|
||||
|
||||
For backwards compatibility, Applications in the argocd namespace can still be referred to as `<project>/<applicationset>` in the RBAC policy rules.
|
||||
For backwards compatibility, Applications in the `argocd` namespace will still be referred to as `<project>/<applicationset>` in the RBAC policy rules.
|
||||
|
||||
!!! note
|
||||
|
||||
Due to backward compatibility, it is not possible to define RBAC policies specifically for applications in the Argo CD control plane namespace (typically `argocd`) using the pattern `foo/argocd/*`. Applications in the control plane namespace are always normalized to the 2-segment format `<project>/<application>` in RBAC enforcement. For security reasons, an AppProject should never grant access to the control plane namespace through the `.spec.sourceNamespaces` field, as this would allow users to create applications with elevated privileges.
|
||||
|
||||
Wildcards do not make any distinction between project and applicationset namespaces yet. For example, the following RBAC rule would match any application belonging to project foo, regardless of the namespace it is created in:
|
||||
|
||||
|
|
|
|||
|
|
@ -180,7 +180,7 @@ spec:
|
|||
|
||||
Repository details are stored in secrets. To configure a repo, create a secret which contains repository details.
|
||||
Consider using [bitnami-labs/sealed-secrets](https://github.com/bitnami-labs/sealed-secrets) to store an encrypted secret definition as a Kubernetes manifest.
|
||||
Each repository must have a `url` field and, depending on whether you connect using HTTPS, SSH, or GitHub App, `username` and `password` (for HTTPS), `sshPrivateKey` (for SSH), or `githubAppPrivateKey` (for GitHub App).
|
||||
Each repository must have a `url` field and, depending on whether you connect using HTTPS, SSH, GitHub App or Azure Service Principal, `username` and `password` (for HTTPS), `sshPrivateKey` (for SSH), `githubAppPrivateKey` (for GitHub App) or `azureServicePrincipalClientSecret` (for Azure Service Principal).
|
||||
Credentials can be scoped to a project using the optional `project` field. When omitted, the credential will be used as the default for all projects without a scoped credential.
|
||||
|
||||
> [!WARNING]
|
||||
|
|
@ -296,6 +296,39 @@ Example for Azure Container Registry/ Azure Devops repositories using Azure work
|
|||
|
||||
Refer to [Azure Container Registry/Azure Repos using Azure Workload Identity](../user-guide/private-repositories.md#azure-container-registryazure-repos-using-azure-workload-identity)
|
||||
|
||||
Example for Azure Service Principal:
|
||||
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: service-principal-for-azure-public-cloud
|
||||
namespace: argocd
|
||||
labels:
|
||||
argocd.argoproj.io/secret-type: repository
|
||||
stringData:
|
||||
type: git
|
||||
url: https://dev.azure.com/my-devops-organization/my-devops-project/_git/my-devops-repo
|
||||
azureServicePrincipalClientId: 12345678-1234-1234-1234-123456789012
|
||||
azureServicePrincipalTenantId: 12345678-1234-1234-1234-123456789012
|
||||
azureServicePrincipalClientSecret: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: service-principal-for-azure-other-cloud
|
||||
namespace: argocd
|
||||
labels:
|
||||
argocd.argoproj.io/secret-type: repository
|
||||
stringData:
|
||||
type: git
|
||||
url: https://dev.azure.com/my-devops-organization/my-devops-project/_git/my-devops-repo
|
||||
azureActiveDirectoryEndpoint: https://login.microsoftonline.de
|
||||
azureServicePrincipalClientId: 12345678-1234-1234-1234-123456789012
|
||||
azureServicePrincipalTenantId: 12345678-1234-1234-1234-123456789012
|
||||
azureServicePrincipalClientSecret: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
|
||||
```
|
||||
|
||||
### Repository Credentials
|
||||
|
||||
If you want to use the same credentials for multiple repositories, you can configure credential templates. Credential templates can carry the same credentials information as repositories.
|
||||
|
|
|
|||
|
|
@ -59,33 +59,37 @@ argocd admin repo generate-spec REPOURL [flags]
|
|||
### Options
|
||||
|
||||
```
|
||||
--bearer-token string bearer token to the Git BitBucket Data Center repository
|
||||
--depth int Specify a custom depth for git clone operations. Unless specified, a full clone is performed using the depth of 0
|
||||
--enable-lfs enable git-lfs (Large File Support) on this repository
|
||||
--enable-oci enable helm-oci (Helm OCI-Based Repository) (only valid for helm type repositories)
|
||||
--force-http-basic-auth whether to force use of basic auth when connecting repository via HTTP
|
||||
--gcp-service-account-key-path string service account key for the Google Cloud Platform
|
||||
--github-app-enterprise-base-url string base url to use when using GitHub Enterprise (e.g. https://ghe.example.com/api/v3
|
||||
--github-app-id int id of the GitHub Application
|
||||
--github-app-installation-id int installation id of the GitHub Application (optional, will be auto-discovered if not provided)
|
||||
--github-app-private-key-path string private key of the GitHub Application
|
||||
-h, --help help for generate-spec
|
||||
--insecure-ignore-host-key disables SSH strict host key checking (deprecated, use --insecure-skip-server-verification instead)
|
||||
--insecure-oci-force-http Use http when accessing an OCI repository
|
||||
--insecure-skip-server-verification disables server certificate and host key checks
|
||||
--name string name of the repository, mandatory for repositories of type helm
|
||||
--no-proxy string don't access these targets via proxy
|
||||
-o, --output string Output format. One of: json|yaml (default "yaml")
|
||||
--password string password to the repository
|
||||
--project string project of the repository
|
||||
--proxy string use proxy to access repository
|
||||
--ssh-private-key-path string path to the private ssh key (e.g. ~/.ssh/id_rsa)
|
||||
--tls-client-cert-key-path string path to the TLS client cert's key (must be PEM format)
|
||||
--tls-client-cert-path string path to the TLS client cert (must be PEM format)
|
||||
--type string type of the repository, "git", "oci" or "helm" (default "git")
|
||||
--use-azure-workload-identity whether to use azure workload identity for authentication
|
||||
--username string username to the repository
|
||||
--webhook-manifest-cache-warm-disabled disable manifest cache warming during webhook processing for this repository (recommended for large monorepos with plain YAML manifests)
|
||||
--azure-active-directory-endpoint string Active Directory endpoint when not using default Azure public cloud (e.g. https://login.microsoftonline.de)
|
||||
--azure-service-principal-client-id string client id of the Azure Service Principal
|
||||
--azure-service-principal-client-secret string client secret of the Azure Service Principal
|
||||
--azure-service-principal-tenant-id string tenant id of the Azure Service Principal
|
||||
--bearer-token string bearer token to the Git BitBucket Data Center repository
|
||||
--depth int Specify a custom depth for git clone operations. Unless specified, a full clone is performed using the depth of 0
|
||||
--enable-lfs enable git-lfs (Large File Support) on this repository
|
||||
--enable-oci enable helm-oci (Helm OCI-Based Repository) (only valid for helm type repositories)
|
||||
--force-http-basic-auth whether to force use of basic auth when connecting repository via HTTP
|
||||
--gcp-service-account-key-path string service account key for the Google Cloud Platform
|
||||
--github-app-enterprise-base-url string base url to use when using GitHub Enterprise (e.g. https://ghe.example.com/api/v3
|
||||
--github-app-id int id of the GitHub Application
|
||||
--github-app-installation-id int installation id of the GitHub Application (optional, will be auto-discovered if not provided)
|
||||
--github-app-private-key-path string private key of the GitHub Application
|
||||
-h, --help help for generate-spec
|
||||
--insecure-ignore-host-key disables SSH strict host key checking (deprecated, use --insecure-skip-server-verification instead)
|
||||
--insecure-oci-force-http Use http when accessing an OCI repository
|
||||
--insecure-skip-server-verification disables server certificate and host key checks
|
||||
--name string name of the repository, mandatory for repositories of type helm
|
||||
--no-proxy string don't access these targets via proxy
|
||||
-o, --output string Output format. One of: json|yaml (default "yaml")
|
||||
--password string password to the repository
|
||||
--project string project of the repository
|
||||
--proxy string use proxy to access repository
|
||||
--ssh-private-key-path string path to the private ssh key (e.g. ~/.ssh/id_rsa)
|
||||
--tls-client-cert-key-path string path to the TLS client cert's key (must be PEM format)
|
||||
--tls-client-cert-path string path to the TLS client cert (must be PEM format)
|
||||
--type string type of the repository, "git", "oci" or "helm" (default "git")
|
||||
--use-azure-workload-identity whether to use azure workload identity for authentication
|
||||
--username string username to the repository
|
||||
--webhook-manifest-cache-warm-disabled disable manifest cache warming during webhook processing for this repository (recommended for large monorepos with plain YAML manifests)
|
||||
```
|
||||
|
||||
### Options inherited from parent commands
|
||||
|
|
|
|||
64
docs/user-guide/commands/argocd_repo_add.md
generated
64
docs/user-guide/commands/argocd_repo_add.md
generated
|
|
@ -56,38 +56,48 @@ argocd repo add REPOURL [flags]
|
|||
# Add a private Git repository on Google Cloud Sources via GCP service account credentials
|
||||
argocd repo add https://source.developers.google.com/p/my-google-cloud-project/r/my-repo --gcp-service-account-key-path service-account-key.json
|
||||
|
||||
# Add a private Git repository on Azure Devops via Azure Service Principal credentials
|
||||
argocd repo add https://dev.azure.com/my-devops-organization/my-devops-project/_git/my-devops-repo --azure-service-principal-client-id 12345678-1234-1234-1234-123456789012 --azure-service-principal-client-secret test --azure-service-principal-tenant-id 12345678-1234-1234-1234-123456789012
|
||||
|
||||
# Add a private Git repository on Azure Devops via Azure Service Principal credentials when not using default Azure public cloud
|
||||
argocd repo add https://dev.azure.com/my-devops-organization/my-devops-project/_git/my-devops-repo --azure-service-principal-client-id 12345678-1234-1234-1234-123456789012 --azure-service-principal-client-secret test --azure-service-principal-tenant-id 12345678-1234-1234-1234-123456789012 --azure-active-directory-endpoint https://login.microsoftonline.de
|
||||
|
||||
```
|
||||
|
||||
### Options
|
||||
|
||||
```
|
||||
--bearer-token string bearer token to the Git BitBucket Data Center repository
|
||||
--depth int Specify a custom depth for git clone operations. Unless specified, a full clone is performed using the depth of 0
|
||||
--enable-lfs enable git-lfs (Large File Support) on this repository
|
||||
--enable-oci enable helm-oci (Helm OCI-Based Repository) (only valid for helm type repositories)
|
||||
--force-http-basic-auth whether to force use of basic auth when connecting repository via HTTP
|
||||
--gcp-service-account-key-path string service account key for the Google Cloud Platform
|
||||
--github-app-enterprise-base-url string base url to use when using GitHub Enterprise (e.g. https://ghe.example.com/api/v3
|
||||
--github-app-id int id of the GitHub Application
|
||||
--github-app-installation-id int installation id of the GitHub Application (optional, will be auto-discovered if not provided)
|
||||
--github-app-private-key-path string private key of the GitHub Application
|
||||
-h, --help help for add
|
||||
--insecure-ignore-host-key disables SSH strict host key checking (deprecated, use --insecure-skip-server-verification instead)
|
||||
--insecure-oci-force-http Use http when accessing an OCI repository
|
||||
--insecure-skip-server-verification disables server certificate and host key checks
|
||||
--name string name of the repository, mandatory for repositories of type helm
|
||||
--no-proxy string don't access these targets via proxy
|
||||
--password string password to the repository
|
||||
--project string project of the repository
|
||||
--proxy string use proxy to access repository
|
||||
--ssh-private-key-path string path to the private ssh key (e.g. ~/.ssh/id_rsa)
|
||||
--tls-client-cert-key-path string path to the TLS client cert's key (must be PEM format)
|
||||
--tls-client-cert-path string path to the TLS client cert (must be PEM format)
|
||||
--type string type of the repository, "git", "oci" or "helm" (default "git")
|
||||
--upsert Override an existing repository with the same name even if the spec differs
|
||||
--use-azure-workload-identity whether to use azure workload identity for authentication
|
||||
--username string username to the repository
|
||||
--webhook-manifest-cache-warm-disabled disable manifest cache warming during webhook processing for this repository (recommended for large monorepos with plain YAML manifests)
|
||||
--azure-active-directory-endpoint string Active Directory endpoint when not using default Azure public cloud (e.g. https://login.microsoftonline.de)
|
||||
--azure-service-principal-client-id string client id of the Azure Service Principal
|
||||
--azure-service-principal-client-secret string client secret of the Azure Service Principal
|
||||
--azure-service-principal-tenant-id string tenant id of the Azure Service Principal
|
||||
--bearer-token string bearer token to the Git BitBucket Data Center repository
|
||||
--depth int Specify a custom depth for git clone operations. Unless specified, a full clone is performed using the depth of 0
|
||||
--enable-lfs enable git-lfs (Large File Support) on this repository
|
||||
--enable-oci enable helm-oci (Helm OCI-Based Repository) (only valid for helm type repositories)
|
||||
--force-http-basic-auth whether to force use of basic auth when connecting repository via HTTP
|
||||
--gcp-service-account-key-path string service account key for the Google Cloud Platform
|
||||
--github-app-enterprise-base-url string base url to use when using GitHub Enterprise (e.g. https://ghe.example.com/api/v3
|
||||
--github-app-id int id of the GitHub Application
|
||||
--github-app-installation-id int installation id of the GitHub Application (optional, will be auto-discovered if not provided)
|
||||
--github-app-private-key-path string private key of the GitHub Application
|
||||
-h, --help help for add
|
||||
--insecure-ignore-host-key disables SSH strict host key checking (deprecated, use --insecure-skip-server-verification instead)
|
||||
--insecure-oci-force-http Use http when accessing an OCI repository
|
||||
--insecure-skip-server-verification disables server certificate and host key checks
|
||||
--name string name of the repository, mandatory for repositories of type helm
|
||||
--no-proxy string don't access these targets via proxy
|
||||
--password string password to the repository
|
||||
--project string project of the repository
|
||||
--proxy string use proxy to access repository
|
||||
--ssh-private-key-path string path to the private ssh key (e.g. ~/.ssh/id_rsa)
|
||||
--tls-client-cert-key-path string path to the TLS client cert's key (must be PEM format)
|
||||
--tls-client-cert-path string path to the TLS client cert (must be PEM format)
|
||||
--type string type of the repository, "git", "oci" or "helm" (default "git")
|
||||
--upsert Override an existing repository with the same name even if the spec differs
|
||||
--use-azure-workload-identity whether to use azure workload identity for authentication
|
||||
--username string username to the repository
|
||||
--webhook-manifest-cache-warm-disabled disable manifest cache warming during webhook processing for this repository (recommended for large monorepos with plain YAML manifests)
|
||||
```
|
||||
|
||||
### Options inherited from parent commands
|
||||
|
|
|
|||
46
docs/user-guide/commands/argocd_repocreds_add.md
generated
46
docs/user-guide/commands/argocd_repocreds_add.md
generated
|
|
@ -32,29 +32,39 @@ argocd repocreds add REPOURL [flags]
|
|||
# Add credentials with GCP credentials for all repositories under https://source.developers.google.com/p/my-google-cloud-project/r/
|
||||
argocd repocreds add https://source.developers.google.com/p/my-google-cloud-project/r/ --gcp-service-account-key-path service-account-key.json
|
||||
|
||||
# Add credentials with Azure Service Principal to use for all repositories under https://dev.azure.com/my-devops-organization
|
||||
argocd repocreds add https://dev.azure.com/my-devops-organization --azure-service-principal-client-id 12345678-1234-1234-1234-123456789012 --azure-service-principal-client-secret test --azure-service-principal-tenant-id 12345678-1234-1234-1234-123456789012
|
||||
|
||||
# Add credentials with Azure Service Principal to use for all repositories under https://dev.azure.com/my-devops-organization when not using default Azure public cloud
|
||||
argocd repocreds add https://dev.azure.com/my-devops-organization --azure-service-principal-client-id 12345678-1234-1234-1234-123456789012 --azure-service-principal-client-secret test --azure-service-principal-tenant-id 12345678-1234-1234-1234-123456789012 --azure-active-directory-endpoint https://login.microsoftonline.de
|
||||
|
||||
```
|
||||
|
||||
### Options
|
||||
|
||||
```
|
||||
--bearer-token string bearer token to the Git repository
|
||||
--enable-oci Specifies whether helm-oci support should be enabled for this repo
|
||||
--force-http-basic-auth whether to force basic auth when connecting via HTTP
|
||||
--gcp-service-account-key-path string service account key for the Google Cloud Platform
|
||||
--github-app-enterprise-base-url string base url to use when using GitHub Enterprise (e.g. https://ghe.example.com/api/v3
|
||||
--github-app-id int id of the GitHub Application
|
||||
--github-app-installation-id int installation id of the GitHub Application (optional, will be auto-discovered if not provided)
|
||||
--github-app-private-key-path string private key of the GitHub Application
|
||||
-h, --help help for add
|
||||
--password string password to the repository
|
||||
--proxy-url string If provided, this URL will be used to connect via proxy
|
||||
--ssh-private-key-path string path to the private ssh key (e.g. ~/.ssh/id_rsa)
|
||||
--tls-client-cert-key-path string path to the TLS client cert's key (must be PEM format)
|
||||
--tls-client-cert-path string path to the TLS client cert (must be PEM format)
|
||||
--type string type of the repository, "git" or "helm" (default "git")
|
||||
--upsert Override an existing repository with the same name even if the spec differs
|
||||
--use-azure-workload-identity whether to use azure workload identity for authentication
|
||||
--username string username to the repository
|
||||
--azure-active-directory-endpoint string Active Directory endpoint when not using default Azure public cloud (e.g. https://login.microsoftonline.de)
|
||||
--azure-service-principal-client-id string client id of the Azure Service Principal
|
||||
--azure-service-principal-client-secret string client secret of the Azure Service Principal
|
||||
--azure-service-principal-tenant-id string tenant id of the Azure Service Principal
|
||||
--bearer-token string bearer token to the Git repository
|
||||
--enable-oci Specifies whether helm-oci support should be enabled for this repo
|
||||
--force-http-basic-auth whether to force basic auth when connecting via HTTP
|
||||
--gcp-service-account-key-path string service account key for the Google Cloud Platform
|
||||
--github-app-enterprise-base-url string base url to use when using GitHub Enterprise (e.g. https://ghe.example.com/api/v3
|
||||
--github-app-id int id of the GitHub Application
|
||||
--github-app-installation-id int installation id of the GitHub Application (optional, will be auto-discovered if not provided)
|
||||
--github-app-private-key-path string private key of the GitHub Application
|
||||
-h, --help help for add
|
||||
--password string password to the repository
|
||||
--proxy-url string If provided, this URL will be used to connect via proxy
|
||||
--ssh-private-key-path string path to the private ssh key (e.g. ~/.ssh/id_rsa)
|
||||
--tls-client-cert-key-path string path to the TLS client cert's key (must be PEM format)
|
||||
--tls-client-cert-path string path to the TLS client cert (must be PEM format)
|
||||
--type string type of the repository, "git" or "helm" (default "git")
|
||||
--upsert Override an existing repository with the same name even if the spec differs
|
||||
--use-azure-workload-identity whether to use azure workload identity for authentication
|
||||
--username string username to the repository
|
||||
```
|
||||
|
||||
### Options inherited from parent commands
|
||||
|
|
|
|||
|
|
@ -242,6 +242,36 @@ stringData:
|
|||
useAzureWorkloadIdentity: "true"
|
||||
```
|
||||
|
||||
### Azure Devops using Service Principal
|
||||
|
||||
Azure DevOps repositories can be accessed using credentials from a Service Principal. Refer to steps 1,2 and 3 from the [Use service principals and managed identities in Azure DevOps](https://learn.microsoft.com/en-us/azure/devops/integrate/get-started/authentication/service-principal-managed-identity?view=azure-devops) documentation on how to create a service principal and configure access to Azure DevOps.
|
||||
|
||||
> [!NOTE]
|
||||
> Ensure your service principal has at least `Project Readers` permissions to the `Project` that contains the repository. This is the minimum requirement.
|
||||
|
||||
You can configure access to your Git repository hosted on Azure DevOps with Service Principal by either using the CLI or the UI.
|
||||
|
||||
Using the CLI:
|
||||
|
||||
```
|
||||
argocd repo add https://dev.azure.com/my-devops-organization/my-devops-project/_git/my-devops-repo --azure-service-principal-tenant-id 12345678-1234-1234-1234-123456789012 --azure-service-principal-client-id 12345678-1234-1234-1234-123456789012 --azure-service-principal-client-secret test
|
||||
```
|
||||
|
||||
> [!NOTE]
|
||||
> To use an Azure cloud other than the default public cloud using the CLI add `--azure-active-directory-endpoint https://login.microsoftonline.de` flag.
|
||||
|
||||
Using the UI:
|
||||
|
||||
1. Navigate to `Settings/Repositories`
|
||||
|
||||

|
||||
|
||||
2. Click `Connect Repo` button, choose connection method: `Via Azure Service Principal`, enter the URL, Tenant Id, Client Id, Client Secret, and Active Directory Endpoint if not using default Azure public cloud.
|
||||
|
||||

|
||||
|
||||
3. Click `Connect` to test the connection and have the repository added
|
||||
|
||||
## Credential templates
|
||||
|
||||
You can also set up credentials to serve as templates for connecting repositories, without having to repeat credential configuration. For example, if you setup credential templates for the URL prefix `https://github.com/argoproj`, these credentials will be used for all repositories with this URL as prefix (e.g. `https://github.com/argoproj/argocd-example-apps`) that do not have their own credentials configured.
|
||||
|
|
|
|||
|
|
@ -1,15 +1,10 @@
|
|||
# Selective Sync
|
||||
|
||||
A *selective sync* is one where only some resources are sync'd. You can choose which resources from the UI:
|
||||
A _selective sync_ is one where only some resources are sync'd. You can choose which resources from the UI or the CLI:
|
||||
|
||||

|
||||
|
||||
When doing so, bear in mind that:
|
||||
|
||||
* Your sync is not recorded in the history, and so rollback is not possible.
|
||||
* [Hooks](sync-waves.md) are not run.
|
||||
|
||||
## Selective Sync Option
|
||||
|
||||
Turning on selective sync option which will sync only out-of-sync resources.
|
||||
See [sync options](sync-options.md#selective-sync) documentation for more details.
|
||||
- Your sync is **not** recorded in the history, and so rollback is not possible.
|
||||
- [Hooks](sync-waves.md) are **not** run.
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ kind: Application
|
|||
spec:
|
||||
syncPolicy:
|
||||
syncOptions:
|
||||
- Prune=false
|
||||
- Prune=false
|
||||
```
|
||||
|
||||
Note that setting a Prune sync option on the resource will always override a
|
||||
|
|
@ -55,14 +55,13 @@ confirmed. The UI will look similar to this, with the "Confirm Pruning" button a
|
|||
|
||||
It is also possible to set this option as a default option on the application level:
|
||||
|
||||
|
||||
```yaml
|
||||
apiVersion: argoproj.io/v1alpha1
|
||||
kind: Application
|
||||
spec:
|
||||
syncPolicy:
|
||||
syncOptions:
|
||||
- Prune=confirm
|
||||
- Prune=confirm
|
||||
```
|
||||
|
||||
Note that setting a Prune sync option on the resource will always override a
|
||||
|
|
@ -85,8 +84,7 @@ If you want to exclude a whole class of objects globally, consider setting `reso
|
|||
When syncing a custom resource which is not yet known to the cluster, there are generally two options:
|
||||
|
||||
1. The CRD manifest is part of the same sync. Then Argo CD will automatically skip the dry run, the CRD will be applied and the resource can be created.
|
||||
2. In some cases the CRD is not part of the sync, but it could be created in another way, e.g. by a controller in the cluster. An example is [gatekeeper](https://github.com/open-policy-agent/gatekeeper),
|
||||
which creates CRDs in response to user defined `ConstraintTemplates`. Argo CD cannot find the CRD in the sync and will fail with the error `the server could not find the requested resource`.
|
||||
2. In some cases the CRD is not part of the sync, but it could be created in another way, e.g. by a controller in the cluster. An example is [gatekeeper](https://github.com/open-policy-agent/gatekeeper), which creates CRDs in response to user defined `ConstraintTemplates`. Argo CD cannot find the CRD in the sync and will fail with the error `the server could not find the requested resource`.
|
||||
|
||||
To skip the dry run for missing resource types, use the following annotation:
|
||||
|
||||
|
|
@ -107,7 +105,7 @@ kind: Application
|
|||
spec:
|
||||
syncPolicy:
|
||||
syncOptions:
|
||||
- SkipDryRunOnMissingResource=true
|
||||
- SkipDryRunOnMissingResource=true
|
||||
```
|
||||
|
||||
## No Resource Deletion
|
||||
|
|
@ -123,14 +121,13 @@ metadata:
|
|||
|
||||
It is also possible to set this option as a default option on the application level:
|
||||
|
||||
|
||||
```yaml
|
||||
apiVersion: argoproj.io/v1alpha1
|
||||
kind: Application
|
||||
spec:
|
||||
syncPolicy:
|
||||
syncOptions:
|
||||
- Delete=false
|
||||
- Delete=false
|
||||
```
|
||||
|
||||
Note that setting a Delete sync option on the resource will always override a
|
||||
|
|
@ -158,21 +155,24 @@ kind: Application
|
|||
spec:
|
||||
syncPolicy:
|
||||
syncOptions:
|
||||
- Delete=confirm
|
||||
- Delete=confirm
|
||||
```
|
||||
|
||||
Note that setting a Delete sync option on the resource will always override a
|
||||
Delete sync policy defined in the Application.
|
||||
|
||||
## Selective Sync
|
||||
## Apply Resources OutOfSync Only
|
||||
|
||||
Currently, when syncing using auto sync Argo CD applies every object in the application.
|
||||
For applications containing thousands of objects this takes quite a long time and puts undue pressure on the api server.
|
||||
Turning on the selective sync option will sync only out-of-sync resources.
|
||||
The default behavior when syncing your application is to apply every object in the application.
|
||||
For applications containing thousands of objects, this takes quite a long time and puts undue pressure on the Kubernetes API server. It will also significantly increase the size of the `status.operationState.syncResult.resources` field, which may impact the Kubernetes database.
|
||||
|
||||
Turning on the sync option will sync only out-of-sync resources.
|
||||
|
||||
Unlike [Selective Sync](./selective_sync.md), when `ApplyOutOfSyncOnly` is enabled, Sync Hooks will still run and the sync will be recorded in the history.
|
||||
|
||||
You can add this option in the following ways:
|
||||
|
||||
1) Add `ApplyOutOfSyncOnly=true` in manifest
|
||||
1. Add `ApplyOutOfSyncOnly=true` in manifest
|
||||
|
||||
Example:
|
||||
|
||||
|
|
@ -182,10 +182,10 @@ kind: Application
|
|||
spec:
|
||||
syncPolicy:
|
||||
syncOptions:
|
||||
- ApplyOutOfSyncOnly=true
|
||||
- ApplyOutOfSyncOnly=true
|
||||
```
|
||||
|
||||
2) Set sync option via argocd cli
|
||||
2. Set sync option via argocd cli
|
||||
|
||||
Example:
|
||||
|
||||
|
|
@ -205,7 +205,7 @@ kind: Application
|
|||
spec:
|
||||
syncPolicy:
|
||||
syncOptions:
|
||||
- PrunePropagationPolicy=foreground
|
||||
- PrunePropagationPolicy=foreground
|
||||
```
|
||||
|
||||
## Prune Last
|
||||
|
|
@ -219,10 +219,11 @@ kind: Application
|
|||
spec:
|
||||
syncPolicy:
|
||||
syncOptions:
|
||||
- PruneLast=true
|
||||
- PruneLast=true
|
||||
```
|
||||
|
||||
This can also be configured at individual resource level.
|
||||
|
||||
```yaml
|
||||
metadata:
|
||||
annotations:
|
||||
|
|
@ -236,14 +237,13 @@ By default, Argo CD executes the `kubectl apply` operation to apply the configur
|
|||
`kubectl.kubernetes.io/last-applied-configuration` annotation that is added by `kubectl apply`. In such cases you
|
||||
might use `Replace=true` sync option:
|
||||
|
||||
|
||||
```yaml
|
||||
apiVersion: argoproj.io/v1alpha1
|
||||
kind: Application
|
||||
spec:
|
||||
syncPolicy:
|
||||
syncOptions:
|
||||
- Replace=true
|
||||
- Replace=true
|
||||
```
|
||||
|
||||
If the `Replace=true` sync option is set, Argo CD will use `kubectl replace` or `kubectl create` command to apply changes.
|
||||
|
|
@ -253,6 +253,7 @@ If the `Replace=true` sync option is set, Argo CD will use `kubectl replace` or
|
|||
> This sync option has the potential to be destructive and might lead to resources having to be recreated, which could cause an outage for your application.
|
||||
|
||||
This can also be configured at individual resource level.
|
||||
|
||||
```yaml
|
||||
metadata:
|
||||
annotations:
|
||||
|
|
@ -268,6 +269,7 @@ For certain resources you might want to delete and recreate, e.g. job resources
|
|||
> This sync option has a destructive action, which could cause an outage for your application.
|
||||
|
||||
In such cases you might use `Force=true` sync option in target resources annotation:
|
||||
|
||||
```yaml
|
||||
metadata:
|
||||
annotations:
|
||||
|
|
@ -302,7 +304,7 @@ kind: Application
|
|||
spec:
|
||||
syncPolicy:
|
||||
syncOptions:
|
||||
- ServerSideApply=true
|
||||
- ServerSideApply=true
|
||||
```
|
||||
|
||||
To enable ServerSideApply just for an individual resource, the sync-option annotation
|
||||
|
|
@ -323,7 +325,6 @@ metadata:
|
|||
argocd.argoproj.io/sync-options: ServerSideApply=false
|
||||
```
|
||||
|
||||
|
||||
ServerSideApply can also be used to patch existing resources by providing a partial
|
||||
yaml. For example, if there is a requirement to update just the number of replicas
|
||||
in a given Deployment, the following yaml can be provided to Argo CD:
|
||||
|
|
@ -338,7 +339,7 @@ spec:
|
|||
```
|
||||
|
||||
Note that by the Deployment schema specification, this isn't a valid manifest. In this
|
||||
case an additional sync option *must* be provided to skip schema validation. The example
|
||||
case an additional sync option _must_ be provided to skip schema validation. The example
|
||||
below shows how to configure the application to enable the two necessary sync options:
|
||||
|
||||
```yaml
|
||||
|
|
@ -347,8 +348,8 @@ kind: Application
|
|||
spec:
|
||||
syncPolicy:
|
||||
syncOptions:
|
||||
- ServerSideApply=true
|
||||
- Validate=false
|
||||
- ServerSideApply=true
|
||||
- Validate=false
|
||||
```
|
||||
|
||||
In this case, Argo CD will use the `kubectl apply --server-side --force-conflicts --validate=false` command
|
||||
|
|
@ -368,7 +369,7 @@ kind: Application
|
|||
spec:
|
||||
syncPolicy:
|
||||
syncOptions:
|
||||
- ClientSideApplyMigration=false
|
||||
- ClientSideApplyMigration=false
|
||||
```
|
||||
|
||||
You can specify a custom field manager for the client-side apply migration using an annotation:
|
||||
|
|
@ -378,7 +379,7 @@ apiVersion: argoproj.io/v1alpha1
|
|||
kind: Application
|
||||
metadata:
|
||||
annotations:
|
||||
argocd.argoproj.io/client-side-apply-migration-manager: "my-custom-manager"
|
||||
argocd.argoproj.io/client-side-apply-migration-manager: 'my-custom-manager'
|
||||
```
|
||||
|
||||
This is useful when you have other operators managing resources that are no longer in use and would like Argo CD to own all the fields for that operator.
|
||||
|
|
@ -386,6 +387,7 @@ This is useful when you have other operators managing resources that are no long
|
|||
### How it works
|
||||
|
||||
When client-side apply migration is enabled:
|
||||
|
||||
1. Argo CD will use the specified field manager (or default if not specified) to perform migration
|
||||
2. During a server-side apply sync operation, it will:
|
||||
- Check if the specified field manager exists in the resource's `managedFields` with `operation: Update` (indicating client-side apply)
|
||||
|
|
@ -405,7 +407,7 @@ kind: Application
|
|||
spec:
|
||||
syncPolicy:
|
||||
syncOptions:
|
||||
- FailOnSharedResource=true
|
||||
- FailOnSharedResource=true
|
||||
```
|
||||
|
||||
## Respect ignore differences configs
|
||||
|
|
@ -416,16 +418,15 @@ This sync option is used to enable Argo CD to consider the configurations made i
|
|||
apiVersion: argoproj.io/v1alpha1
|
||||
kind: Application
|
||||
spec:
|
||||
|
||||
ignoreDifferences:
|
||||
- group: "apps"
|
||||
kind: "Deployment"
|
||||
jsonPointers:
|
||||
- /spec/replicas
|
||||
- group: 'apps'
|
||||
kind: 'Deployment'
|
||||
jsonPointers:
|
||||
- /spec/replicas
|
||||
|
||||
syncPolicy:
|
||||
syncOptions:
|
||||
- RespectIgnoreDifferences=true
|
||||
- RespectIgnoreDifferences=true
|
||||
```
|
||||
|
||||
The example above shows how an Argo CD Application can be configured so it will ignore the `spec.replicas` field from the desired state (git) during the sync stage. This is achieved by calculating and pre-patching the desired state before applying it in the cluster. Note that the `RespectIgnoreDifferences` sync option is only effective when the resource is already created in the cluster. If the Application is being created and no live state exists, the desired state is applied as-is.
|
||||
|
|
@ -443,7 +444,7 @@ spec:
|
|||
namespace: some-namespace
|
||||
syncPolicy:
|
||||
syncOptions:
|
||||
- CreateNamespace=true
|
||||
- CreateNamespace=true
|
||||
```
|
||||
|
||||
The example above shows how an Argo CD Application can be configured so it will create the namespace specified in `spec.destination.namespace` if it doesn't exist already. Without this either declared in the Application manifest or passed in the CLI via `--sync-option CreateNamespace=true`, the Application will fail to sync if the namespace doesn't exist.
|
||||
|
|
@ -471,7 +472,7 @@ spec:
|
|||
applies: for
|
||||
annotations: on-the-namespace
|
||||
syncOptions:
|
||||
- CreateNamespace=true
|
||||
- CreateNamespace=true
|
||||
```
|
||||
|
||||
In order for Argo CD to manage the labels and annotations on the namespace, `CreateNamespace=true` needs to be set as a
|
||||
|
|
@ -479,14 +480,14 @@ sync option, otherwise nothing will happen. If the namespace doesn't already exi
|
|||
already have labels and/or annotations set on it, you're good to go.
|
||||
|
||||
The generated namespace is normally not tracked with Argo CD. You can use `managedNamespaceMetadata` to
|
||||
set a tracking annotation on the generated namespace, which sets the namespace to be *owned* by Argo CD.
|
||||
set a tracking annotation on the generated namespace, which sets the namespace to be _owned_ by Argo CD.
|
||||
|
||||
Once a namespace is owned by Argo CD, it will be managed by ArgoCD, including the possibility to delete it, which Argo CD normally does not do:
|
||||
|
||||
```yaml
|
||||
managedNamespaceMetadata:
|
||||
annotations:
|
||||
argocd.argoproj.io/tracking-id: "your-application-name:/Namespace:/your-namespace-name"
|
||||
argocd.argoproj.io/tracking-id: 'your-application-name:/Namespace:/your-namespace-name'
|
||||
```
|
||||
|
||||
> [!NOTE]
|
||||
|
|
@ -500,7 +501,7 @@ client-side-applied resources with server-side-applies. If you do not upgrade th
|
|||
may remove existing labels/annotations, which may or may not be the desired behavior.
|
||||
|
||||
Another thing to keep mind of is that if you have a k8s manifest for the same namespace in your Argo CD application, that
|
||||
will take precedence and *overwrite whatever values that have been set in `managedNamespaceMetadata`*. In other words, if
|
||||
will take precedence and **overwrite whatever values that have been set in `managedNamespaceMetadata`**. In other words, if
|
||||
you have an application that sets `managedNamespaceMetadata`
|
||||
|
||||
```yaml
|
||||
|
|
@ -530,7 +531,7 @@ metadata:
|
|||
The resulting namespace will have its annotations set to
|
||||
|
||||
```yaml
|
||||
annotations:
|
||||
foo: bar
|
||||
something: completely-different
|
||||
annotations:
|
||||
foo: bar
|
||||
something: completely-different
|
||||
```
|
||||
|
|
|
|||
5
go.mod
5
go.mod
|
|
@ -119,7 +119,7 @@ require (
|
|||
layeh.com/gopher-json v0.0.0-20190114024228-97fed8db8427
|
||||
oras.land/oras-go/v2 v2.6.0
|
||||
sigs.k8s.io/controller-runtime v0.21.0
|
||||
sigs.k8s.io/structured-merge-diff/v6 v6.3.2
|
||||
sigs.k8s.io/structured-merge-diff/v6 v6.4.0
|
||||
sigs.k8s.io/yaml v1.6.0
|
||||
)
|
||||
|
||||
|
|
@ -148,12 +148,11 @@ require (
|
|||
github.com/ProtonMail/go-crypto v1.1.6 // indirect
|
||||
github.com/RocketChat/Rocket.Chat.Go.SDK v0.0.0-20240116134246-a8cbe886bab0 // indirect
|
||||
github.com/aws/aws-sdk-go-v2 v1.41.5
|
||||
github.com/aws/aws-sdk-go-v2/config v1.32.14
|
||||
github.com/aws/aws-sdk-go-v2/config v1.32.15
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.19.14
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.21 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.21 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.21 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.6 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.7 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.21 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/signin v1.0.9 // indirect
|
||||
|
|
|
|||
10
go.sum
10
go.sum
|
|
@ -126,8 +126,8 @@ github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkY
|
|||
github.com/aws/aws-sdk-go v1.44.39/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo=
|
||||
github.com/aws/aws-sdk-go-v2 v1.41.5 h1:dj5kopbwUsVUVFgO4Fi5BIT3t4WyqIDjGKCangnV/yY=
|
||||
github.com/aws/aws-sdk-go-v2 v1.41.5/go.mod h1:mwsPRE8ceUUpiTgF7QmQIJ7lgsKUPQOUl3o72QBrE1o=
|
||||
github.com/aws/aws-sdk-go-v2/config v1.32.14 h1:opVIRo/ZbbI8OIqSOKmpFaY7IwfFUOCCXBsUpJOwDdI=
|
||||
github.com/aws/aws-sdk-go-v2/config v1.32.14/go.mod h1:U4/V0uKxh0Tl5sxmCBZ3AecYny4UNlVmObYjKuuaiOo=
|
||||
github.com/aws/aws-sdk-go-v2/config v1.32.15 h1:i7rHbaySnBXGvCkDndaBU8f3EAlRVgViwNfkwFUrXgE=
|
||||
github.com/aws/aws-sdk-go-v2/config v1.32.15/go.mod h1:yLJzL0IkI9+4BwjPSOueyHzppJj3t0dhK5tbmmcFk5Q=
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.19.14 h1:n+UcGWAIZHkXzYt87uMFBv/l8THYELoX6gVcUvgl6fI=
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.19.14/go.mod h1:cJKuyWB59Mqi0jM3nFYQRmnHVQIcgoxjEMAbLkpr62w=
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.21 h1:NUS3K4BTDArQqNu2ih7yeDLaS3bmHD0YndtA6UP884g=
|
||||
|
|
@ -136,8 +136,6 @@ github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.21 h1:Rgg6wvjjtX8bNHcvi
|
|||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.21/go.mod h1:A/kJFst/nm//cyqonihbdpQZwiUhhzpqTsdbhDdRF9c=
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.21 h1:PEgGVtPoB6NTpPrBgqSE5hE/o47Ij9qk/SEZFbUOe9A=
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.21/go.mod h1:p+hz+PRAYlY3zcpJhPwXlLC4C+kqn70WIHwnzAfs6ps=
|
||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.6 h1:qYQ4pzQ2Oz6WpQ8T3HvGHnZydA72MnLuFK9tJwmrbHw=
|
||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.6/go.mod h1:O3h0IK87yXci+kg6flUKzJnWeziQUKciKrLjcatSNcY=
|
||||
github.com/aws/aws-sdk-go-v2/service/codecommit v1.33.12 h1:yv3mfWt/eiDTTry6fkN5hh8wHJfU5ygnw+DJp10C0/c=
|
||||
github.com/aws/aws-sdk-go-v2/service/codecommit v1.33.12/go.mod h1:voO3LP/dZ4CTERiNWCz3DFLbK/8hbfeC1OJkLW+sang=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.7 h1:5EniKhLZe4xzL7a+fU3C2tfUN4nWIqlLesfrjkuPFTY=
|
||||
|
|
@ -1517,8 +1515,8 @@ sigs.k8s.io/randfill v1.0.0 h1:JfjMILfT8A6RbawdsK2JXGBR5AQVfd+9TbzrlneTyrU=
|
|||
sigs.k8s.io/randfill v1.0.0/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY=
|
||||
sigs.k8s.io/structured-merge-diff/v6 v6.2.0/go.mod h1:M3W8sfWvn2HhQDIbGWj3S099YozAsymCo/wrT5ohRUE=
|
||||
sigs.k8s.io/structured-merge-diff/v6 v6.3.0/go.mod h1:M3W8sfWvn2HhQDIbGWj3S099YozAsymCo/wrT5ohRUE=
|
||||
sigs.k8s.io/structured-merge-diff/v6 v6.3.2 h1:kwVWMx5yS1CrnFWA/2QHyRVJ8jM6dBA80uLmm0wJkk8=
|
||||
sigs.k8s.io/structured-merge-diff/v6 v6.3.2/go.mod h1:M3W8sfWvn2HhQDIbGWj3S099YozAsymCo/wrT5ohRUE=
|
||||
sigs.k8s.io/structured-merge-diff/v6 v6.4.0 h1:qmp2e3ZfFi1/jJbDGpD4mt3wyp6PE1NfKHCYLqgNQJo=
|
||||
sigs.k8s.io/structured-merge-diff/v6 v6.4.0/go.mod h1:M3W8sfWvn2HhQDIbGWj3S099YozAsymCo/wrT5ohRUE=
|
||||
sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=
|
||||
sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY=
|
||||
sigs.k8s.io/yaml v1.6.0 h1:G8fkbMSAFqgEFgh4b1wmtzDnioxFCUgTZhlbj5P9QYs=
|
||||
|
|
|
|||
|
|
@ -84,7 +84,7 @@ func (generator *ApplicationGenerator) Generate(opts *util.GenerateOpts) error {
|
|||
return err
|
||||
}
|
||||
log.Printf("Pick destination %q", destination)
|
||||
log.Printf("Create application")
|
||||
log.Print("Create application")
|
||||
_, err = applications.Create(context.TODO(), &v1alpha1.Application{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
GenerateName: "application-",
|
||||
|
|
@ -105,7 +105,7 @@ func (generator *ApplicationGenerator) Generate(opts *util.GenerateOpts) error {
|
|||
}
|
||||
|
||||
func (generator *ApplicationGenerator) Clean(opts *util.GenerateOpts) error {
|
||||
log.Printf("Clean applications")
|
||||
log.Print("Clean applications")
|
||||
applications := generator.argoClientSet.ArgoprojV1alpha1().Applications(opts.Namespace)
|
||||
return applications.DeleteCollection(context.TODO(), metav1.DeleteOptions{}, metav1.ListOptions{
|
||||
LabelSelector: "app.kubernetes.io/generated-by=argocd-generator",
|
||||
|
|
|
|||
|
|
@ -251,7 +251,7 @@ func (cg *ClusterGenerator) Generate(opts *util.GenerateOpts) error {
|
|||
}
|
||||
|
||||
func (cg *ClusterGenerator) Clean(opts *util.GenerateOpts) error {
|
||||
log.Printf("Clean clusters")
|
||||
log.Print("Clean clusters")
|
||||
namespaces, err := cg.clientSet.CoreV1().Namespaces().List(context.TODO(), metav1.ListOptions{})
|
||||
if err != nil {
|
||||
return err
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ func (pg *ProjectGenerator) Generate(opts *util.GenerateOpts) error {
|
|||
}
|
||||
|
||||
func (pg *ProjectGenerator) Clean(opts *util.GenerateOpts) error {
|
||||
log.Printf("Clean projects")
|
||||
log.Print("Clean projects")
|
||||
projects := pg.clientSet.ArgoprojV1alpha1().AppProjects(opts.Namespace)
|
||||
return projects.DeleteCollection(context.TODO(), metav1.DeleteOptions{}, metav1.ListOptions{
|
||||
LabelSelector: "app.kubernetes.io/generated-by=argocd-generator",
|
||||
|
|
|
|||
|
|
@ -117,7 +117,7 @@ func (rg *RepoGenerator) Generate(opts *util.GenerateOpts) error {
|
|||
}
|
||||
|
||||
func (rg *RepoGenerator) Clean(opts *util.GenerateOpts) error {
|
||||
log.Printf("Clean repos")
|
||||
log.Print("Clean repos")
|
||||
secrets := rg.clientSet.CoreV1().Secrets(opts.Namespace)
|
||||
return secrets.DeleteCollection(context.TODO(), metav1.DeleteOptions{}, metav1.ListOptions{
|
||||
LabelSelector: "app.kubernetes.io/generated-by=argocd-generator",
|
||||
|
|
|
|||
405
pkg/apiclient/repository/repository.pb.go
generated
405
pkg/apiclient/repository/repository.pb.go
generated
|
|
@ -401,10 +401,18 @@ type RepoAccessQuery struct {
|
|||
// BearerToken contains the bearer token used for Git auth at the repo server
|
||||
BearerToken string `protobuf:"bytes,21,opt,name=bearerToken,proto3" json:"bearerToken,omitempty"`
|
||||
// Whether https should be disabled for an OCI repo
|
||||
InsecureOciForceHttp bool `protobuf:"varint,22,opt,name=insecureOciForceHttp,proto3" json:"insecureOciForceHttp,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
InsecureOciForceHttp bool `protobuf:"varint,22,opt,name=insecureOciForceHttp,proto3" json:"insecureOciForceHttp,omitempty"`
|
||||
// Azure Service Principal Client ID
|
||||
AzureServicePrincipalClientId string `protobuf:"bytes,23,opt,name=azureServicePrincipalClientId,proto3" json:"azureServicePrincipalClientId,omitempty"`
|
||||
// Azure Service Principal Client Secret
|
||||
AzureServicePrincipalClientSecret string `protobuf:"bytes,24,opt,name=azureServicePrincipalClientSecret,proto3" json:"azureServicePrincipalClientSecret,omitempty"`
|
||||
// Azure Service Principal Tenant ID
|
||||
AzureServicePrincipalTenantId string `protobuf:"bytes,25,opt,name=azureServicePrincipalTenantId,proto3" json:"azureServicePrincipalTenantId,omitempty"`
|
||||
// Azure Active Directory Endpoint
|
||||
AzureActiveDirectoryEndpoint string `protobuf:"bytes,26,opt,name=azureActiveDirectoryEndpoint,proto3" json:"azureActiveDirectoryEndpoint,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
}
|
||||
|
||||
func (m *RepoAccessQuery) Reset() { *m = RepoAccessQuery{} }
|
||||
|
|
@ -587,6 +595,34 @@ func (m *RepoAccessQuery) GetInsecureOciForceHttp() bool {
|
|||
return false
|
||||
}
|
||||
|
||||
func (m *RepoAccessQuery) GetAzureServicePrincipalClientId() string {
|
||||
if m != nil {
|
||||
return m.AzureServicePrincipalClientId
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *RepoAccessQuery) GetAzureServicePrincipalClientSecret() string {
|
||||
if m != nil {
|
||||
return m.AzureServicePrincipalClientSecret
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *RepoAccessQuery) GetAzureServicePrincipalTenantId() string {
|
||||
if m != nil {
|
||||
return m.AzureServicePrincipalTenantId
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *RepoAccessQuery) GetAzureActiveDirectoryEndpoint() string {
|
||||
if m != nil {
|
||||
return m.AzureActiveDirectoryEndpoint
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type RepoResponse struct {
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
|
|
@ -757,94 +793,99 @@ func init() {
|
|||
}
|
||||
|
||||
var fileDescriptor_8d38260443475705 = []byte{
|
||||
// 1392 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x58, 0xdf, 0x6e, 0x1b, 0xc5,
|
||||
0x17, 0xd6, 0x26, 0x8d, 0x9b, 0x4c, 0x9a, 0xd6, 0x9d, 0x24, 0xed, 0xfe, 0xdc, 0x34, 0xcd, 0x6f,
|
||||
0x5b, 0xa2, 0x34, 0x6a, 0xd7, 0x4d, 0x0a, 0xa2, 0x2a, 0x02, 0xc9, 0x4d, 0x4a, 0x6b, 0x11, 0x91,
|
||||
0xb2, 0x6d, 0xa9, 0x84, 0x40, 0x68, 0xb2, 0x3e, 0xb1, 0xb7, 0xd9, 0xec, 0x4e, 0x67, 0xc6, 0x6e,
|
||||
0x4d, 0xd5, 0x1b, 0x84, 0x10, 0x12, 0xdc, 0x20, 0x04, 0xe2, 0x0e, 0x2e, 0x90, 0x90, 0xe0, 0x12,
|
||||
0x89, 0x67, 0xe0, 0x12, 0x89, 0x17, 0x40, 0x15, 0x0f, 0xc1, 0x25, 0x9a, 0x33, 0xeb, 0xf5, 0x3a,
|
||||
0xf1, 0x9f, 0x44, 0x4d, 0x73, 0x37, 0x73, 0xce, 0xec, 0xf9, 0xbe, 0xf3, 0xcd, 0x99, 0x33, 0x63,
|
||||
0x13, 0x47, 0x82, 0x68, 0x80, 0x28, 0x0a, 0xe0, 0xb1, 0x0c, 0x54, 0x2c, 0x9a, 0x99, 0xa1, 0xcb,
|
||||
0x45, 0xac, 0x62, 0x4a, 0xda, 0x96, 0xc2, 0x4c, 0x35, 0x8e, 0xab, 0x21, 0x14, 0x19, 0x0f, 0x8a,
|
||||
0x2c, 0x8a, 0x62, 0xc5, 0x54, 0x10, 0x47, 0xd2, 0xac, 0x2c, 0xac, 0x55, 0x03, 0x55, 0xab, 0x6f,
|
||||
0xb8, 0x7e, 0xbc, 0x5d, 0x64, 0xa2, 0x1a, 0x73, 0x11, 0x3f, 0xc4, 0xc1, 0x65, 0xbf, 0x52, 0x6c,
|
||||
0x5c, 0x2d, 0xf2, 0xad, 0xaa, 0xfe, 0x52, 0x16, 0x19, 0xe7, 0x61, 0xe0, 0xe3, 0xb7, 0xc5, 0xc6,
|
||||
0x12, 0x0b, 0x79, 0x8d, 0x2d, 0x15, 0xab, 0x10, 0x81, 0x60, 0x0a, 0x2a, 0x49, 0xb4, 0x9b, 0x03,
|
||||
0xa2, 0x21, 0xad, 0x81, 0xf4, 0x9d, 0x26, 0x99, 0xf0, 0x80, 0xc7, 0x25, 0xce, 0xe5, 0x7b, 0x75,
|
||||
0x10, 0x4d, 0x4a, 0xc9, 0x11, 0xbd, 0xc8, 0xb6, 0xe6, 0xac, 0x85, 0x31, 0x0f, 0xc7, 0xb4, 0x40,
|
||||
0x46, 0x05, 0x34, 0x02, 0x19, 0xc4, 0x91, 0x3d, 0x84, 0xf6, 0x74, 0x4e, 0x6d, 0x72, 0x94, 0x71,
|
||||
0xfe, 0x2e, 0xdb, 0x06, 0x7b, 0x18, 0x5d, 0xad, 0x29, 0x9d, 0x25, 0x84, 0x71, 0x7e, 0x47, 0xc4,
|
||||
0x0f, 0xc1, 0x57, 0xf6, 0x11, 0x74, 0x66, 0x2c, 0xce, 0x12, 0x39, 0x5a, 0xe2, 0xbc, 0x1c, 0x6d,
|
||||
0xc6, 0x1a, 0x54, 0x35, 0x39, 0xb4, 0x40, 0xf5, 0x58, 0xdb, 0x38, 0x53, 0xb5, 0x04, 0x10, 0xc7,
|
||||
0xce, 0xbf, 0x16, 0x99, 0x4c, 0xe8, 0xae, 0x82, 0x62, 0x41, 0x98, 0x90, 0xae, 0x92, 0x9c, 0x8c,
|
||||
0xeb, 0xc2, 0x37, 0x11, 0xc6, 0x97, 0xd7, 0xdd, 0xb6, 0x3a, 0x6e, 0x4b, 0x1d, 0x1c, 0x7c, 0xec,
|
||||
0x57, 0xdc, 0xc6, 0x55, 0x97, 0x6f, 0x55, 0x5d, 0xad, 0xb5, 0x9b, 0xd1, 0xda, 0x6d, 0x69, 0xed,
|
||||
0x96, 0xda, 0xc6, 0xbb, 0x18, 0xd6, 0x4b, 0xc2, 0x67, 0xb3, 0x1d, 0xea, 0x97, 0xed, 0xf0, 0xce,
|
||||
0x6c, 0xe9, 0x1c, 0x19, 0x37, 0x31, 0xca, 0x51, 0x05, 0x9e, 0xa0, 0x1c, 0x23, 0x5e, 0xd6, 0x44,
|
||||
0x67, 0xc8, 0x58, 0x03, 0x84, 0x16, 0xb5, 0x5c, 0xb1, 0x47, 0xd0, 0xdf, 0x36, 0x38, 0x6f, 0x92,
|
||||
0x7c, 0x6b, 0xa3, 0x3c, 0x90, 0x3c, 0x8e, 0x24, 0xd0, 0x8b, 0x64, 0x24, 0x50, 0xb0, 0x2d, 0x6d,
|
||||
0x6b, 0x6e, 0x78, 0x61, 0x7c, 0x79, 0xd2, 0xcd, 0x6c, 0x6f, 0x22, 0xad, 0x67, 0x56, 0x38, 0x3e,
|
||||
0x19, 0xd3, 0x9f, 0xf7, 0xde, 0x63, 0x87, 0x1c, 0xdb, 0x8c, 0x75, 0xaa, 0xb0, 0x29, 0x40, 0x1a,
|
||||
0xd9, 0x47, 0xbd, 0x0e, 0xdb, 0xa0, 0x1c, 0x9d, 0xdf, 0x72, 0xe4, 0x04, 0x92, 0xf4, 0x7d, 0x90,
|
||||
0xfd, 0xeb, 0xa9, 0x2e, 0x41, 0x44, 0x6d, 0x19, 0xd3, 0xb9, 0xf6, 0x71, 0x26, 0xe5, 0xe3, 0x58,
|
||||
0x54, 0x12, 0x84, 0x74, 0x4e, 0x2f, 0x90, 0x09, 0x29, 0x6b, 0x77, 0x44, 0xd0, 0x60, 0x0a, 0xde,
|
||||
0x81, 0x66, 0x52, 0x54, 0x9d, 0x46, 0x1d, 0x21, 0x88, 0x24, 0xf8, 0x75, 0x01, 0x28, 0xe3, 0xa8,
|
||||
0x97, 0xce, 0xe9, 0x25, 0x72, 0x52, 0x85, 0x72, 0x25, 0x0c, 0x20, 0x52, 0x2b, 0x20, 0xd4, 0x2a,
|
||||
0x53, 0xcc, 0xce, 0x61, 0x94, 0xdd, 0x0e, 0xba, 0x48, 0xf2, 0x1d, 0x46, 0x0d, 0x79, 0x14, 0x17,
|
||||
0xef, 0xb2, 0xa7, 0x25, 0x3c, 0xd6, 0x59, 0xc2, 0x98, 0x23, 0x31, 0x36, 0xcc, 0x6f, 0x86, 0x8c,
|
||||
0x41, 0xc4, 0x36, 0x42, 0x58, 0xf7, 0x03, 0x7b, 0x1c, 0xe9, 0xb5, 0x0d, 0xf4, 0x0a, 0x99, 0x34,
|
||||
0x95, 0x5b, 0xd2, 0xaa, 0xa6, 0x79, 0x1e, 0xc3, 0x00, 0xdd, 0x5c, 0xba, 0xae, 0x52, 0x73, 0x79,
|
||||
0xd5, 0x9e, 0x98, 0xb3, 0x16, 0x86, 0xbd, 0xac, 0x89, 0x5e, 0x23, 0xa7, 0xdb, 0xd3, 0x48, 0x2a,
|
||||
0x16, 0x86, 0x58, 0xda, 0xe5, 0x55, 0xfb, 0x38, 0xae, 0xee, 0xe5, 0xa6, 0x6f, 0x91, 0x42, 0xea,
|
||||
0xba, 0x19, 0x29, 0x10, 0x5c, 0x04, 0x12, 0x6e, 0x30, 0x09, 0xf7, 0x45, 0x68, 0x9f, 0x40, 0x52,
|
||||
0x7d, 0x56, 0xd0, 0x29, 0x32, 0xc2, 0x45, 0xfc, 0xa4, 0x69, 0xe7, 0x71, 0xa9, 0x99, 0xe8, 0x33,
|
||||
0xc4, 0x93, 0x12, 0x3a, 0x69, 0xce, 0x50, 0x32, 0xa5, 0xcb, 0x64, 0xaa, 0xea, 0xf3, 0xbb, 0x20,
|
||||
0x1a, 0x81, 0x0f, 0x25, 0xdf, 0x8f, 0xeb, 0x11, 0x6a, 0x4e, 0x71, 0x59, 0x57, 0x1f, 0x75, 0x09,
|
||||
0xc5, 0x1a, 0xbd, 0xad, 0x14, 0xbf, 0xc1, 0x64, 0xe0, 0x97, 0xea, 0xaa, 0x66, 0x4f, 0xa2, 0xb0,
|
||||
0x5d, 0x3c, 0xf4, 0x3a, 0xb1, 0xeb, 0x12, 0x4a, 0x9f, 0xd4, 0x05, 0x3c, 0x88, 0xc5, 0x56, 0x18,
|
||||
0xb3, 0x4a, 0xb9, 0x02, 0x91, 0x0a, 0x54, 0xd3, 0x9e, 0xc2, 0xaf, 0x7a, 0xfa, 0xb5, 0xd6, 0x1b,
|
||||
0xc0, 0x04, 0x88, 0x7b, 0xf1, 0x16, 0x44, 0xf6, 0x34, 0xd2, 0xca, 0x9a, 0x74, 0x06, 0xad, 0x5a,
|
||||
0x5b, 0xf7, 0x83, 0xb7, 0x5b, 0xf0, 0xf6, 0x29, 0x8c, 0xdc, 0xd5, 0xe7, 0x1c, 0x27, 0xc7, 0xf4,
|
||||
0xa1, 0x69, 0x9d, 0x6a, 0xe7, 0x67, 0x8b, 0x9c, 0xd4, 0x86, 0x15, 0x01, 0x4c, 0x81, 0x07, 0x8f,
|
||||
0xea, 0x20, 0x15, 0xfd, 0x30, 0x73, 0x8e, 0xc6, 0x97, 0x6f, 0xbf, 0x58, 0x83, 0xf3, 0xd2, 0x3e,
|
||||
0x91, 0x9c, 0xc8, 0x53, 0x24, 0x57, 0xe7, 0x12, 0x84, 0x4a, 0xce, 0x7d, 0x32, 0xd3, 0xd5, 0xea,
|
||||
0x0b, 0xa8, 0xc8, 0xf5, 0x28, 0x6c, 0xe2, 0x71, 0x1c, 0xf5, 0xda, 0x06, 0xe7, 0x91, 0x21, 0x7a,
|
||||
0x9f, 0x57, 0x0e, 0x8b, 0xe8, 0xf2, 0x67, 0xa7, 0x0d, 0xa6, 0x31, 0x26, 0xe5, 0x40, 0xbf, 0xb2,
|
||||
0xc8, 0x91, 0xb5, 0x40, 0x2a, 0x3a, 0x9d, 0x6d, 0x81, 0x69, 0xc3, 0x2b, 0xac, 0x1d, 0x14, 0x0b,
|
||||
0x0d, 0xe2, 0x9c, 0xfb, 0xf4, 0xaf, 0x7f, 0xbe, 0x19, 0x3a, 0x45, 0xa7, 0xf0, 0xa2, 0x6f, 0x2c,
|
||||
0xb5, 0x6f, 0xd5, 0x00, 0xe4, 0x17, 0x43, 0x16, 0xfd, 0xd2, 0x22, 0xc3, 0xb7, 0xa0, 0x27, 0x9b,
|
||||
0x03, 0xd3, 0xc4, 0x39, 0x8f, 0x4c, 0xce, 0xd2, 0x33, 0xdd, 0x98, 0x14, 0x9f, 0xea, 0xd9, 0x33,
|
||||
0xfa, 0x9d, 0x45, 0x46, 0x6f, 0x81, 0x7a, 0x20, 0x02, 0x05, 0x2f, 0x9f, 0xd2, 0x45, 0xa4, 0x74,
|
||||
0x9e, 0xfe, 0xbf, 0x45, 0xe9, 0xb1, 0xc6, 0xbd, 0xdc, 0x8d, 0xd8, 0xb7, 0x16, 0xc9, 0x6b, 0x41,
|
||||
0xbd, 0x8c, 0xef, 0x70, 0x76, 0x70, 0xa6, 0xdf, 0x0e, 0xd2, 0x1f, 0x2d, 0x32, 0xad, 0x97, 0xa1,
|
||||
0x62, 0x87, 0x4f, 0xce, 0x41, 0x72, 0x33, 0xb4, 0xd0, 0x5b, 0x41, 0xfa, 0x11, 0x19, 0x35, 0xca,
|
||||
0x6d, 0xf6, 0x24, 0x95, 0xef, 0x34, 0x6f, 0x4a, 0x67, 0x01, 0x03, 0x3b, 0x74, 0xae, 0x4f, 0xb5,
|
||||
0x14, 0x85, 0x0e, 0x59, 0x21, 0xe3, 0x3a, 0xfc, 0xfa, 0x4a, 0xf9, 0x1e, 0xab, 0xee, 0x03, 0xe1,
|
||||
0x12, 0x22, 0xcc, 0xd3, 0x0b, 0xfd, 0x10, 0x62, 0x3f, 0xb8, 0xac, 0x74, 0xd8, 0x6d, 0x93, 0x84,
|
||||
0x7e, 0xd2, 0xd0, 0xff, 0xed, 0x84, 0x48, 0x5f, 0xa4, 0x85, 0x99, 0x6e, 0xae, 0xb4, 0x5b, 0xee,
|
||||
0x29, 0x29, 0xa6, 0x21, 0xbe, 0xb6, 0xc8, 0xc4, 0x2d, 0x50, 0xed, 0xb7, 0x23, 0x3d, 0xd7, 0x25,
|
||||
0x72, 0xf6, 0x5d, 0x59, 0x70, 0x7a, 0x2f, 0x48, 0x09, 0xbc, 0x81, 0x04, 0x5e, 0x73, 0xae, 0x74,
|
||||
0x27, 0x60, 0x5e, 0x78, 0x18, 0xe7, 0xbe, 0xb7, 0x86, 0x54, 0x2a, 0x26, 0xc2, 0x75, 0x6b, 0x91,
|
||||
0x36, 0x90, 0xd2, 0x6d, 0x08, 0xb7, 0x57, 0x6a, 0x4c, 0xa8, 0x9e, 0x52, 0xcf, 0x66, 0xcd, 0xed,
|
||||
0xe5, 0x29, 0x09, 0x17, 0x49, 0x2c, 0xd0, 0xf9, 0x7e, 0x2a, 0xd4, 0x20, 0xdc, 0xf6, 0x0d, 0xcc,
|
||||
0xf7, 0x16, 0xc9, 0x99, 0xfb, 0x85, 0x9e, 0xdd, 0x89, 0xd8, 0x71, 0xef, 0x1c, 0x60, 0x67, 0x78,
|
||||
0xc5, 0xd4, 0xb5, 0xd3, 0xf5, 0xd0, 0x5d, 0xc7, 0xf6, 0xae, 0x9b, 0xe7, 0x0f, 0x16, 0xc9, 0xb7,
|
||||
0x28, 0xb4, 0xbe, 0x3d, 0x3c, 0x92, 0xce, 0x60, 0x92, 0xf4, 0x17, 0x8b, 0x4c, 0x1b, 0xfc, 0xce,
|
||||
0x0e, 0x71, 0x88, 0x34, 0x93, 0xaa, 0x77, 0xfa, 0xf4, 0x88, 0x84, 0xec, 0x4f, 0x16, 0xc9, 0x99,
|
||||
0x0b, 0x7a, 0x37, 0xbb, 0x8e, 0x8b, 0xfb, 0x00, 0xd9, 0x2d, 0x99, 0x6a, 0x2c, 0xf4, 0x39, 0x93,
|
||||
0x48, 0xe5, 0x59, 0x7b, 0xd7, 0x7f, 0xb5, 0x48, 0xbe, 0x45, 0xa7, 0xb7, 0x9c, 0x2f, 0x8b, 0xb0,
|
||||
0xbb, 0x3f, 0xc2, 0xf4, 0x77, 0x8b, 0x4c, 0x1b, 0x2e, 0x03, 0x2b, 0xe0, 0x65, 0x51, 0x7e, 0x15,
|
||||
0x29, 0xbb, 0x85, 0xf9, 0x41, 0xf7, 0x6c, 0x07, 0x71, 0x46, 0x72, 0xab, 0x10, 0x42, 0xef, 0x87,
|
||||
0x80, 0xbd, 0xd3, 0x9c, 0xb6, 0x98, 0x79, 0xf3, 0xd6, 0x58, 0xec, 0xf7, 0xd6, 0xd0, 0x3b, 0x59,
|
||||
0x23, 0x79, 0x03, 0x91, 0x51, 0x65, 0xdf, 0x60, 0xe7, 0xf7, 0x00, 0x46, 0x25, 0x99, 0x36, 0x48,
|
||||
0x3b, 0x37, 0x61, 0xdf, 0x70, 0xc9, 0xa3, 0x65, 0x71, 0x0f, 0x8f, 0x96, 0xa7, 0xe4, 0xf8, 0xfb,
|
||||
0x2c, 0x0c, 0xf4, 0xa6, 0x9a, 0x9f, 0xb9, 0xf4, 0xcc, 0xae, 0x4b, 0xa2, 0xfd, 0xf3, 0xb7, 0x0f,
|
||||
0xe6, 0x32, 0x62, 0x5e, 0x72, 0xfa, 0xde, 0x95, 0x8d, 0x04, 0x2a, 0xd9, 0xbe, 0xcf, 0x2d, 0x32,
|
||||
0xd9, 0x42, 0xc7, 0xa4, 0x5f, 0x8c, 0xc2, 0x35, 0xa4, 0xb0, 0xec, 0x2c, 0x0e, 0x4c, 0x7b, 0x07,
|
||||
0x91, 0x1b, 0x37, 0xff, 0x78, 0x3e, 0x6b, 0xfd, 0xf9, 0x7c, 0xd6, 0xfa, 0xfb, 0xf9, 0xac, 0xf5,
|
||||
0xc1, 0xeb, 0x7b, 0xfb, 0x67, 0xcb, 0xc7, 0x1f, 0xcc, 0x99, 0xff, 0xa0, 0x36, 0x72, 0xf8, 0x27,
|
||||
0xd4, 0xd5, 0xff, 0x02, 0x00, 0x00, 0xff, 0xff, 0xbc, 0x0b, 0xd2, 0x3f, 0x69, 0x13, 0x00, 0x00,
|
||||
// 1471 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x58, 0x5f, 0x6f, 0x13, 0xc7,
|
||||
0x16, 0xd7, 0x26, 0x24, 0x24, 0x13, 0x02, 0x66, 0x92, 0xc0, 0x62, 0x42, 0x08, 0x0b, 0x37, 0x0a,
|
||||
0x11, 0xac, 0x49, 0xb8, 0x57, 0x17, 0x71, 0x75, 0x2b, 0x39, 0x7f, 0x0a, 0x56, 0xa3, 0x86, 0x1a,
|
||||
0x28, 0x52, 0xd5, 0xaa, 0x9a, 0xac, 0x4f, 0xec, 0x25, 0x9b, 0xdd, 0x61, 0x66, 0x6c, 0x70, 0x11,
|
||||
0x2f, 0x55, 0x55, 0x55, 0x6a, 0x5f, 0xaa, 0xaa, 0x55, 0xdf, 0xda, 0x87, 0x4a, 0x95, 0xda, 0xf7,
|
||||
0x7e, 0x86, 0x3e, 0xb6, 0xea, 0x17, 0xa8, 0x50, 0x3f, 0x44, 0x1f, 0xab, 0x39, 0xb3, 0x5e, 0xaf,
|
||||
0x13, 0x7b, 0x9d, 0x88, 0x90, 0xb7, 0x9d, 0x73, 0x8e, 0xcf, 0xef, 0x77, 0x7e, 0x73, 0xf6, 0xcc,
|
||||
0x78, 0x89, 0x23, 0x41, 0x34, 0x40, 0x14, 0x04, 0xf0, 0x48, 0xfa, 0x2a, 0x12, 0xcd, 0xd4, 0xa3,
|
||||
0xcb, 0x45, 0xa4, 0x22, 0x4a, 0xda, 0x96, 0xfc, 0x74, 0x35, 0x8a, 0xaa, 0x01, 0x14, 0x18, 0xf7,
|
||||
0x0b, 0x2c, 0x0c, 0x23, 0xc5, 0x94, 0x1f, 0x85, 0xd2, 0x44, 0xe6, 0xd7, 0xab, 0xbe, 0xaa, 0xd5,
|
||||
0x37, 0x5d, 0x2f, 0xda, 0x29, 0x30, 0x51, 0x8d, 0xb8, 0x88, 0x1e, 0xe3, 0xc3, 0x75, 0xaf, 0x52,
|
||||
0x68, 0xdc, 0x2c, 0xf0, 0xed, 0xaa, 0xfe, 0xa5, 0x2c, 0x30, 0xce, 0x03, 0xdf, 0xc3, 0xdf, 0x16,
|
||||
0x1a, 0x8b, 0x2c, 0xe0, 0x35, 0xb6, 0x58, 0xa8, 0x42, 0x08, 0x82, 0x29, 0xa8, 0xc4, 0xd9, 0xd6,
|
||||
0xfa, 0x64, 0x43, 0x5a, 0x7d, 0xe9, 0x3b, 0x4d, 0x32, 0x5e, 0x06, 0x1e, 0x15, 0x39, 0x97, 0xef,
|
||||
0xd4, 0x41, 0x34, 0x29, 0x25, 0xc7, 0x74, 0x90, 0x6d, 0xcd, 0x5a, 0xf3, 0xa3, 0x65, 0x7c, 0xa6,
|
||||
0x79, 0x32, 0x22, 0xa0, 0xe1, 0x4b, 0x3f, 0x0a, 0xed, 0x01, 0xb4, 0x27, 0x6b, 0x6a, 0x93, 0xe3,
|
||||
0x8c, 0xf3, 0xb7, 0xd9, 0x0e, 0xd8, 0x83, 0xe8, 0x6a, 0x2d, 0xe9, 0x0c, 0x21, 0x8c, 0xf3, 0x7b,
|
||||
0x22, 0x7a, 0x0c, 0x9e, 0xb2, 0x8f, 0xa1, 0x33, 0x65, 0x71, 0x16, 0xc9, 0xf1, 0x22, 0xe7, 0xa5,
|
||||
0x70, 0x2b, 0xd2, 0xa0, 0xaa, 0xc9, 0xa1, 0x05, 0xaa, 0x9f, 0xb5, 0x8d, 0x33, 0x55, 0x8b, 0x01,
|
||||
0xf1, 0xd9, 0xf9, 0xdb, 0x22, 0x13, 0x31, 0xdd, 0x55, 0x50, 0xcc, 0x0f, 0x62, 0xd2, 0x55, 0x32,
|
||||
0x2c, 0xa3, 0xba, 0xf0, 0x4c, 0x86, 0xb1, 0xa5, 0x0d, 0xb7, 0xad, 0x8e, 0xdb, 0x52, 0x07, 0x1f,
|
||||
0x3e, 0xf4, 0x2a, 0x6e, 0xe3, 0xa6, 0xcb, 0xb7, 0xab, 0xae, 0xd6, 0xda, 0x4d, 0x69, 0xed, 0xb6,
|
||||
0xb4, 0x76, 0x8b, 0x6d, 0xe3, 0x7d, 0x4c, 0x5b, 0x8e, 0xd3, 0xa7, 0xab, 0x1d, 0xc8, 0xaa, 0x76,
|
||||
0x70, 0x77, 0xb5, 0x74, 0x96, 0x8c, 0x99, 0x1c, 0xa5, 0xb0, 0x02, 0xcf, 0x50, 0x8e, 0xa1, 0x72,
|
||||
0xda, 0x44, 0xa7, 0xc9, 0x68, 0x03, 0x84, 0x16, 0xb5, 0x54, 0xb1, 0x87, 0xd0, 0xdf, 0x36, 0x38,
|
||||
0xff, 0x27, 0xb9, 0xd6, 0x46, 0x95, 0x41, 0xf2, 0x28, 0x94, 0x40, 0xaf, 0x92, 0x21, 0x5f, 0xc1,
|
||||
0x8e, 0xb4, 0xad, 0xd9, 0xc1, 0xf9, 0xb1, 0xa5, 0x09, 0x37, 0xb5, 0xbd, 0xb1, 0xb4, 0x65, 0x13,
|
||||
0xe1, 0x78, 0x64, 0x54, 0xff, 0xbc, 0xf7, 0x1e, 0x3b, 0xe4, 0xc4, 0x56, 0xa4, 0x4b, 0x85, 0x2d,
|
||||
0x01, 0xd2, 0xc8, 0x3e, 0x52, 0xee, 0xb0, 0xf5, 0xab, 0xd1, 0xf9, 0x7d, 0x84, 0x9c, 0x42, 0x92,
|
||||
0x9e, 0x07, 0x32, 0xbb, 0x9f, 0xea, 0x12, 0x44, 0xd8, 0x96, 0x31, 0x59, 0x6b, 0x1f, 0x67, 0x52,
|
||||
0x3e, 0x8d, 0x44, 0x25, 0x46, 0x48, 0xd6, 0xf4, 0x0a, 0x19, 0x97, 0xb2, 0x76, 0x4f, 0xf8, 0x0d,
|
||||
0xa6, 0xe0, 0x2d, 0x68, 0xc6, 0x4d, 0xd5, 0x69, 0xd4, 0x19, 0xfc, 0x50, 0x82, 0x57, 0x17, 0x80,
|
||||
0x32, 0x8e, 0x94, 0x93, 0x35, 0xbd, 0x46, 0x4e, 0xab, 0x40, 0xae, 0x04, 0x3e, 0x84, 0x6a, 0x05,
|
||||
0x84, 0x5a, 0x65, 0x8a, 0xd9, 0xc3, 0x98, 0x65, 0xaf, 0x83, 0x2e, 0x90, 0x5c, 0x87, 0x51, 0x43,
|
||||
0x1e, 0xc7, 0xe0, 0x3d, 0xf6, 0xa4, 0x85, 0x47, 0x3b, 0x5b, 0x18, 0x6b, 0x24, 0xc6, 0x86, 0xf5,
|
||||
0x4d, 0x93, 0x51, 0x08, 0xd9, 0x66, 0x00, 0x1b, 0x9e, 0x6f, 0x8f, 0x21, 0xbd, 0xb6, 0x81, 0xde,
|
||||
0x20, 0x13, 0xa6, 0x73, 0x8b, 0x5a, 0xd5, 0xa4, 0xce, 0x13, 0x98, 0xa0, 0x9b, 0x4b, 0xf7, 0x55,
|
||||
0x62, 0x2e, 0xad, 0xda, 0xe3, 0xb3, 0xd6, 0xfc, 0x60, 0x39, 0x6d, 0xa2, 0xb7, 0xc8, 0xd9, 0xf6,
|
||||
0x32, 0x94, 0x8a, 0x05, 0x01, 0xb6, 0x76, 0x69, 0xd5, 0x3e, 0x89, 0xd1, 0xbd, 0xdc, 0xf4, 0x0d,
|
||||
0x92, 0x4f, 0x5c, 0x6b, 0xa1, 0x02, 0xc1, 0x85, 0x2f, 0x61, 0x99, 0x49, 0x78, 0x28, 0x02, 0xfb,
|
||||
0x14, 0x92, 0xca, 0x88, 0xa0, 0x93, 0x64, 0x88, 0x8b, 0xe8, 0x59, 0xd3, 0xce, 0x61, 0xa8, 0x59,
|
||||
0xe8, 0x77, 0x88, 0xc7, 0x2d, 0x74, 0xda, 0xbc, 0x43, 0xf1, 0x92, 0x2e, 0x91, 0xc9, 0xaa, 0xc7,
|
||||
0xef, 0x83, 0x68, 0xf8, 0x1e, 0x14, 0x3d, 0x2f, 0xaa, 0x87, 0xa8, 0x39, 0xc5, 0xb0, 0xae, 0x3e,
|
||||
0xea, 0x12, 0x8a, 0x3d, 0x7a, 0x57, 0x29, 0xbe, 0xcc, 0xa4, 0xef, 0x15, 0xeb, 0xaa, 0x66, 0x4f,
|
||||
0xa0, 0xb0, 0x5d, 0x3c, 0xf4, 0x36, 0xb1, 0xeb, 0x12, 0x8a, 0x1f, 0xd5, 0x05, 0x3c, 0x8a, 0xc4,
|
||||
0x76, 0x10, 0xb1, 0x4a, 0xa9, 0x02, 0xa1, 0xf2, 0x55, 0xd3, 0x9e, 0xc4, 0x5f, 0xf5, 0xf4, 0x6b,
|
||||
0xad, 0x37, 0x81, 0x09, 0x10, 0x0f, 0xa2, 0x6d, 0x08, 0xed, 0x29, 0xa4, 0x95, 0x36, 0xe9, 0x0a,
|
||||
0x5a, 0xbd, 0xb6, 0xe1, 0xf9, 0x6f, 0xb6, 0xe0, 0xed, 0x33, 0x98, 0xb9, 0xab, 0x8f, 0xae, 0x92,
|
||||
0x0b, 0x4c, 0xc3, 0xc5, 0xb5, 0xdd, 0x13, 0x7e, 0xe8, 0xf9, 0x9c, 0x05, 0xa6, 0xbf, 0x4a, 0x15,
|
||||
0xfb, 0x2c, 0xe2, 0x64, 0x07, 0xd1, 0x75, 0x72, 0x29, 0x23, 0xe0, 0x3e, 0x78, 0x02, 0x94, 0x6d,
|
||||
0x63, 0xa6, 0xfe, 0x81, 0x3d, 0x39, 0x3d, 0x80, 0x90, 0x21, 0xa7, 0x73, 0x19, 0x9c, 0x5a, 0x41,
|
||||
0x74, 0x99, 0x4c, 0x63, 0x40, 0xd1, 0x53, 0x7e, 0x03, 0x56, 0x7d, 0x01, 0x9e, 0x9e, 0x4d, 0x6b,
|
||||
0x61, 0x85, 0x47, 0x7e, 0xa8, 0xec, 0x3c, 0x26, 0xc9, 0x8c, 0x71, 0x4e, 0x92, 0x13, 0x7a, 0xa4,
|
||||
0xb4, 0x66, 0x9e, 0xf3, 0xa3, 0x45, 0x4e, 0x6b, 0xc3, 0x8a, 0x00, 0xa6, 0xa0, 0x0c, 0x4f, 0xea,
|
||||
0x20, 0x15, 0x7d, 0x3f, 0x35, 0x65, 0xc6, 0x96, 0xee, 0xbe, 0xda, 0xf8, 0x2f, 0x27, 0x53, 0x34,
|
||||
0x9e, 0x57, 0x67, 0xc8, 0x70, 0x9d, 0x4b, 0x10, 0x2a, 0x9e, 0x8a, 0xf1, 0x4a, 0xbf, 0xcb, 0x9e,
|
||||
0x80, 0x8a, 0xdc, 0x08, 0x83, 0x26, 0x0e, 0xab, 0x91, 0x72, 0xdb, 0xe0, 0x3c, 0x31, 0x44, 0x1f,
|
||||
0xf2, 0xca, 0x51, 0x11, 0x5d, 0xfa, 0xe4, 0xac, 0xc1, 0x34, 0xc6, 0x78, 0x5f, 0xe8, 0x17, 0x16,
|
||||
0x39, 0xb6, 0xee, 0x4b, 0x45, 0xa7, 0xd2, 0x07, 0x44, 0x72, 0x1c, 0xe4, 0xd7, 0x0f, 0x8b, 0x85,
|
||||
0x06, 0x71, 0x2e, 0x7e, 0xfc, 0xc7, 0x5f, 0x5f, 0x0d, 0x9c, 0xa1, 0x93, 0x78, 0x0d, 0x6a, 0x2c,
|
||||
0xb6, 0xef, 0x1c, 0x3e, 0xc8, 0xcf, 0x06, 0x2c, 0xfa, 0xb9, 0x45, 0x06, 0xef, 0x40, 0x4f, 0x36,
|
||||
0x87, 0xa6, 0x89, 0x73, 0x19, 0x99, 0x5c, 0xa0, 0xe7, 0xbb, 0x31, 0x29, 0x3c, 0xd7, 0xab, 0x17,
|
||||
0xf4, 0x1b, 0x8b, 0x8c, 0xdc, 0x01, 0xf5, 0x48, 0xf8, 0x0a, 0x5e, 0x3f, 0xa5, 0xab, 0x48, 0xe9,
|
||||
0x32, 0xbd, 0xd4, 0xa2, 0xf4, 0x54, 0xe3, 0x5e, 0xef, 0x46, 0xec, 0x6b, 0x8b, 0xe4, 0xb4, 0xa0,
|
||||
0xe5, 0x94, 0xef, 0x68, 0x76, 0x70, 0x3a, 0x6b, 0x07, 0xe9, 0xf7, 0x16, 0x99, 0xd2, 0x61, 0xa8,
|
||||
0xd8, 0xd1, 0x93, 0x73, 0x90, 0xdc, 0x34, 0xcd, 0xf7, 0x56, 0x90, 0x7e, 0x40, 0x46, 0x8c, 0x72,
|
||||
0x5b, 0x3d, 0x49, 0xe5, 0x3a, 0xcd, 0x5b, 0xd2, 0x99, 0xc7, 0xc4, 0x0e, 0x9d, 0xcd, 0xe8, 0x96,
|
||||
0x82, 0xd0, 0x29, 0x2b, 0x64, 0x4c, 0xa7, 0xdf, 0x58, 0x29, 0x3d, 0x60, 0xd5, 0x03, 0x20, 0x5c,
|
||||
0x43, 0x84, 0x39, 0x7a, 0x25, 0x0b, 0x21, 0xf2, 0xfc, 0xeb, 0x4a, 0xa7, 0xdd, 0x31, 0x45, 0xe8,
|
||||
0x0b, 0x1f, 0x3d, 0xb7, 0x1b, 0x22, 0xb9, 0xaf, 0xe7, 0xa7, 0xbb, 0xb9, 0x92, 0x69, 0xb9, 0xaf,
|
||||
0xa2, 0x98, 0x86, 0xf8, 0xd2, 0x22, 0xe3, 0x77, 0x40, 0xb5, 0x6f, 0xd6, 0xf4, 0x62, 0x97, 0xcc,
|
||||
0xe9, 0x5b, 0x77, 0xde, 0xe9, 0x1d, 0x90, 0x10, 0xf8, 0x1f, 0x12, 0xf8, 0x8f, 0x73, 0xa3, 0x3b,
|
||||
0x01, 0x73, 0xff, 0xc5, 0x3c, 0x0f, 0xcb, 0xeb, 0x48, 0xa5, 0x62, 0x32, 0xdc, 0xb6, 0x16, 0x68,
|
||||
0x03, 0x29, 0xdd, 0x85, 0x60, 0x67, 0xa5, 0xc6, 0x84, 0xea, 0x29, 0xf5, 0x4c, 0xda, 0xdc, 0x0e,
|
||||
0x4f, 0x48, 0xb8, 0x48, 0x62, 0x9e, 0xce, 0x65, 0xa9, 0x50, 0x83, 0x60, 0xc7, 0x33, 0x30, 0xdf,
|
||||
0x5a, 0x64, 0xd8, 0x9c, 0x2f, 0xf4, 0xc2, 0x6e, 0xc4, 0x8e, 0x73, 0xe7, 0x10, 0x27, 0xc3, 0xbf,
|
||||
0x4c, 0x5f, 0x3b, 0x5d, 0x5f, 0xba, 0xdb, 0x38, 0xde, 0xf5, 0xf0, 0xfc, 0xce, 0x22, 0xb9, 0x16,
|
||||
0x85, 0xd6, 0x6f, 0x8f, 0x8e, 0xa4, 0xd3, 0x9f, 0x24, 0xfd, 0xc9, 0x22, 0x53, 0x06, 0xbf, 0x73,
|
||||
0x42, 0x1c, 0x21, 0xcd, 0xb8, 0xeb, 0x9d, 0x8c, 0x19, 0x11, 0x93, 0xfd, 0xc1, 0x22, 0xc3, 0xe6,
|
||||
0x80, 0xde, 0xcb, 0xae, 0xe3, 0xe0, 0x3e, 0x44, 0x76, 0x8b, 0xa6, 0x1b, 0xf3, 0x19, 0xef, 0x24,
|
||||
0x52, 0x79, 0xd1, 0xde, 0xf5, 0x9f, 0x2d, 0x92, 0x6b, 0xd1, 0xe9, 0x2d, 0xe7, 0xeb, 0x22, 0xec,
|
||||
0x1e, 0x8c, 0x30, 0xfd, 0xc5, 0x22, 0x53, 0x86, 0x4b, 0xdf, 0x0e, 0x78, 0x5d, 0x94, 0xff, 0x8d,
|
||||
0x94, 0xdd, 0xfc, 0x5c, 0xbf, 0x73, 0xb6, 0x83, 0x38, 0x23, 0xc3, 0xab, 0x10, 0x40, 0xef, 0x8b,
|
||||
0x80, 0xbd, 0xdb, 0x9c, 0x8c, 0x98, 0x39, 0x73, 0xd7, 0x58, 0xc8, 0xba, 0x6b, 0xe8, 0x9d, 0xac,
|
||||
0x91, 0x9c, 0x81, 0x48, 0xa9, 0x72, 0x60, 0xb0, 0xcb, 0xfb, 0x00, 0xa3, 0x92, 0x4c, 0x19, 0xa4,
|
||||
0xdd, 0x9b, 0x70, 0x60, 0xb8, 0xf8, 0xd2, 0xb2, 0xb0, 0x8f, 0x4b, 0xcb, 0x73, 0x72, 0xf2, 0x5d,
|
||||
0x16, 0xf8, 0x7a, 0x53, 0xcd, 0x47, 0x00, 0x7a, 0x7e, 0xcf, 0x21, 0xd1, 0xfe, 0x38, 0x90, 0x81,
|
||||
0xb9, 0x84, 0x98, 0xd7, 0x9c, 0xcc, 0xb3, 0xb2, 0x11, 0x43, 0xc5, 0xdb, 0xf7, 0xa9, 0x45, 0x26,
|
||||
0x5a, 0xe8, 0x58, 0xf4, 0xab, 0x51, 0xb8, 0x85, 0x14, 0x96, 0x9c, 0x85, 0xbe, 0x65, 0xef, 0x22,
|
||||
0xb2, 0xbc, 0xf6, 0xeb, 0xcb, 0x19, 0xeb, 0xb7, 0x97, 0x33, 0xd6, 0x9f, 0x2f, 0x67, 0xac, 0xf7,
|
||||
0xfe, 0xbb, 0xbf, 0xef, 0x7e, 0x1e, 0xfe, 0xff, 0x4a, 0x7d, 0xa1, 0xdb, 0x1c, 0xc6, 0x4f, 0x74,
|
||||
0x37, 0xff, 0x09, 0x00, 0x00, 0xff, 0xff, 0xff, 0x54, 0xba, 0x9b, 0x87, 0x14, 0x00, 0x00,
|
||||
}
|
||||
|
||||
// Reference imports to suppress errors if they are not otherwise used.
|
||||
|
|
@ -1964,6 +2005,42 @@ func (m *RepoAccessQuery) MarshalToSizedBuffer(dAtA []byte) (int, error) {
|
|||
i -= len(m.XXX_unrecognized)
|
||||
copy(dAtA[i:], m.XXX_unrecognized)
|
||||
}
|
||||
if len(m.AzureActiveDirectoryEndpoint) > 0 {
|
||||
i -= len(m.AzureActiveDirectoryEndpoint)
|
||||
copy(dAtA[i:], m.AzureActiveDirectoryEndpoint)
|
||||
i = encodeVarintRepository(dAtA, i, uint64(len(m.AzureActiveDirectoryEndpoint)))
|
||||
i--
|
||||
dAtA[i] = 0x1
|
||||
i--
|
||||
dAtA[i] = 0xd2
|
||||
}
|
||||
if len(m.AzureServicePrincipalTenantId) > 0 {
|
||||
i -= len(m.AzureServicePrincipalTenantId)
|
||||
copy(dAtA[i:], m.AzureServicePrincipalTenantId)
|
||||
i = encodeVarintRepository(dAtA, i, uint64(len(m.AzureServicePrincipalTenantId)))
|
||||
i--
|
||||
dAtA[i] = 0x1
|
||||
i--
|
||||
dAtA[i] = 0xca
|
||||
}
|
||||
if len(m.AzureServicePrincipalClientSecret) > 0 {
|
||||
i -= len(m.AzureServicePrincipalClientSecret)
|
||||
copy(dAtA[i:], m.AzureServicePrincipalClientSecret)
|
||||
i = encodeVarintRepository(dAtA, i, uint64(len(m.AzureServicePrincipalClientSecret)))
|
||||
i--
|
||||
dAtA[i] = 0x1
|
||||
i--
|
||||
dAtA[i] = 0xc2
|
||||
}
|
||||
if len(m.AzureServicePrincipalClientId) > 0 {
|
||||
i -= len(m.AzureServicePrincipalClientId)
|
||||
copy(dAtA[i:], m.AzureServicePrincipalClientId)
|
||||
i = encodeVarintRepository(dAtA, i, uint64(len(m.AzureServicePrincipalClientId)))
|
||||
i--
|
||||
dAtA[i] = 0x1
|
||||
i--
|
||||
dAtA[i] = 0xba
|
||||
}
|
||||
if m.InsecureOciForceHttp {
|
||||
i--
|
||||
if m.InsecureOciForceHttp {
|
||||
|
|
@ -2477,6 +2554,22 @@ func (m *RepoAccessQuery) Size() (n int) {
|
|||
if m.InsecureOciForceHttp {
|
||||
n += 3
|
||||
}
|
||||
l = len(m.AzureServicePrincipalClientId)
|
||||
if l > 0 {
|
||||
n += 2 + l + sovRepository(uint64(l))
|
||||
}
|
||||
l = len(m.AzureServicePrincipalClientSecret)
|
||||
if l > 0 {
|
||||
n += 2 + l + sovRepository(uint64(l))
|
||||
}
|
||||
l = len(m.AzureServicePrincipalTenantId)
|
||||
if l > 0 {
|
||||
n += 2 + l + sovRepository(uint64(l))
|
||||
}
|
||||
l = len(m.AzureActiveDirectoryEndpoint)
|
||||
if l > 0 {
|
||||
n += 2 + l + sovRepository(uint64(l))
|
||||
}
|
||||
if m.XXX_unrecognized != nil {
|
||||
n += len(m.XXX_unrecognized)
|
||||
}
|
||||
|
|
@ -3857,6 +3950,134 @@ func (m *RepoAccessQuery) Unmarshal(dAtA []byte) error {
|
|||
}
|
||||
}
|
||||
m.InsecureOciForceHttp = bool(v != 0)
|
||||
case 23:
|
||||
if wireType != 2 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field AzureServicePrincipalClientId", wireType)
|
||||
}
|
||||
var stringLen uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowRepository
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
stringLen |= uint64(b&0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
intStringLen := int(stringLen)
|
||||
if intStringLen < 0 {
|
||||
return ErrInvalidLengthRepository
|
||||
}
|
||||
postIndex := iNdEx + intStringLen
|
||||
if postIndex < 0 {
|
||||
return ErrInvalidLengthRepository
|
||||
}
|
||||
if postIndex > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
m.AzureServicePrincipalClientId = string(dAtA[iNdEx:postIndex])
|
||||
iNdEx = postIndex
|
||||
case 24:
|
||||
if wireType != 2 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field AzureServicePrincipalClientSecret", wireType)
|
||||
}
|
||||
var stringLen uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowRepository
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
stringLen |= uint64(b&0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
intStringLen := int(stringLen)
|
||||
if intStringLen < 0 {
|
||||
return ErrInvalidLengthRepository
|
||||
}
|
||||
postIndex := iNdEx + intStringLen
|
||||
if postIndex < 0 {
|
||||
return ErrInvalidLengthRepository
|
||||
}
|
||||
if postIndex > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
m.AzureServicePrincipalClientSecret = string(dAtA[iNdEx:postIndex])
|
||||
iNdEx = postIndex
|
||||
case 25:
|
||||
if wireType != 2 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field AzureServicePrincipalTenantId", wireType)
|
||||
}
|
||||
var stringLen uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowRepository
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
stringLen |= uint64(b&0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
intStringLen := int(stringLen)
|
||||
if intStringLen < 0 {
|
||||
return ErrInvalidLengthRepository
|
||||
}
|
||||
postIndex := iNdEx + intStringLen
|
||||
if postIndex < 0 {
|
||||
return ErrInvalidLengthRepository
|
||||
}
|
||||
if postIndex > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
m.AzureServicePrincipalTenantId = string(dAtA[iNdEx:postIndex])
|
||||
iNdEx = postIndex
|
||||
case 26:
|
||||
if wireType != 2 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field AzureActiveDirectoryEndpoint", wireType)
|
||||
}
|
||||
var stringLen uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowRepository
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
stringLen |= uint64(b&0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
intStringLen := int(stringLen)
|
||||
if intStringLen < 0 {
|
||||
return ErrInvalidLengthRepository
|
||||
}
|
||||
postIndex := iNdEx + intStringLen
|
||||
if postIndex < 0 {
|
||||
return ErrInvalidLengthRepository
|
||||
}
|
||||
if postIndex > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
m.AzureActiveDirectoryEndpoint = string(dAtA[iNdEx:postIndex])
|
||||
iNdEx = postIndex
|
||||
default:
|
||||
iNdEx = preIndex
|
||||
skippy, err := skipRepository(dAtA[iNdEx:])
|
||||
|
|
|
|||
1917
pkg/apis/application/v1alpha1/generated.pb.go
generated
1917
pkg/apis/application/v1alpha1/generated.pb.go
generated
File diff suppressed because it is too large
Load diff
|
|
@ -1876,6 +1876,18 @@ message RepoCreds {
|
|||
|
||||
// InsecureOCIForceHttp specifies whether the connection to the repository uses TLS at _all_. If true, no TLS. This flag is applicable for OCI repos only.
|
||||
optional bool insecureOCIForceHttp = 26;
|
||||
|
||||
// AzureServicePrincipalClientId specifies the client ID of the Azure Service Principal used to access the repo
|
||||
optional string azureServicePrincipalClientId = 29;
|
||||
|
||||
// AzureServicePrincipalClientSecret specifies the client secret of the Azure Service Principal used to access the repo
|
||||
optional string azureServicePrincipalClientSecret = 30;
|
||||
|
||||
// AzureServicePrincipalTenantId specifies the tenant ID of the Azure Service Principal used to access the repo
|
||||
optional string azureServicePrincipalTenantId = 31;
|
||||
|
||||
// AzureActiveDirectoryEndpoint specifies the Azure Active Directory endpoint used for Service Principal authentication. If empty will default to https://login.microsoftonline.com
|
||||
optional string azureActiveDirectoryEndpoint = 32;
|
||||
}
|
||||
|
||||
// RepositoryList is a collection of Repositories.
|
||||
|
|
@ -1973,6 +1985,18 @@ message Repository {
|
|||
// When set, webhook handlers will only trigger reconciliation for affected applications and skip Redis cache
|
||||
// operations for unaffected ones. Recommended for large monorepos with plain YAML manifests.
|
||||
optional bool webhookManifestCacheWarmDisabled = 28;
|
||||
|
||||
// AzureServicePrincipalClientId specifies the client ID of the Azure Service Principal used to access the repo
|
||||
optional string azureServicePrincipalClientId = 29;
|
||||
|
||||
// AzureServicePrincipalClientSecret specifies the client secret of the Azure Service Principal used to access the repo
|
||||
optional string azureServicePrincipalClientSecret = 30;
|
||||
|
||||
// AzureServicePrincipalTenantId specifies the tenant ID of the Azure Service Principal used to access the repo
|
||||
optional string azureServicePrincipalTenantId = 31;
|
||||
|
||||
// AzureActiveDirectoryEndpoint specifies the Azure Active Directory endpoint used for Service Principal authentication. If empty will default to https://login.microsoftonline.com
|
||||
optional string azureActiveDirectoryEndpoint = 32;
|
||||
}
|
||||
|
||||
// A RepositoryCertificate is either SSH known hosts entry or TLS certificate
|
||||
|
|
|
|||
|
|
@ -57,6 +57,14 @@ type RepoCreds struct {
|
|||
BearerToken string `json:"bearerToken,omitempty" protobuf:"bytes,25,opt,name=bearerToken"`
|
||||
// InsecureOCIForceHttp specifies whether the connection to the repository uses TLS at _all_. If true, no TLS. This flag is applicable for OCI repos only.
|
||||
InsecureOCIForceHttp bool `json:"insecureOCIForceHttp,omitempty" protobuf:"bytes,26,opt,name=insecureOCIForceHttp"` //nolint:revive //FIXME(var-naming)
|
||||
// AzureServicePrincipalClientId specifies the client ID of the Azure Service Principal used to access the repo
|
||||
AzureServicePrincipalClientId string `json:"azureServicePrincipalClientId,omitempty" protobuf:"bytes,29,opt,name=azureServicePrincipalClientId"`
|
||||
// AzureServicePrincipalClientSecret specifies the client secret of the Azure Service Principal used to access the repo
|
||||
AzureServicePrincipalClientSecret string `json:"azureServicePrincipalClientSecret,omitempty" protobuf:"bytes,30,opt,name=azureServicePrincipalClientSecret"`
|
||||
// AzureServicePrincipalTenantId specifies the tenant ID of the Azure Service Principal used to access the repo
|
||||
AzureServicePrincipalTenantId string `json:"azureServicePrincipalTenantId,omitempty" protobuf:"bytes,31,opt,name=azureServicePrincipalTenantId"`
|
||||
// AzureActiveDirectoryEndpoint specifies the Azure Active Directory endpoint used for Service Principal authentication. If empty will default to https://login.microsoftonline.com
|
||||
AzureActiveDirectoryEndpoint string `json:"azureActiveDirectoryEndpoint,omitempty" protobuf:"bytes,32,opt,name=azureActiveDirectoryEndpoint"`
|
||||
}
|
||||
|
||||
// Repository is a repository holding application configurations
|
||||
|
|
@ -120,6 +128,14 @@ type Repository struct {
|
|||
// When set, webhook handlers will only trigger reconciliation for affected applications and skip Redis cache
|
||||
// operations for unaffected ones. Recommended for large monorepos with plain YAML manifests.
|
||||
WebhookManifestCacheWarmDisabled bool `json:"webhookManifestCacheWarmDisabled,omitempty" protobuf:"varint,28,opt,name=webhookManifestCacheWarmDisabled"`
|
||||
// AzureServicePrincipalClientId specifies the client ID of the Azure Service Principal used to access the repo
|
||||
AzureServicePrincipalClientId string `json:"azureServicePrincipalClientId,omitempty" protobuf:"bytes,29,opt,name=azureServicePrincipalClientId"`
|
||||
// AzureServicePrincipalClientSecret specifies the client secret of the Azure Service Principal used to access the repo
|
||||
AzureServicePrincipalClientSecret string `json:"azureServicePrincipalClientSecret,omitempty" protobuf:"bytes,30,opt,name=azureServicePrincipalClientSecret"`
|
||||
// AzureServicePrincipalTenantId specifies the tenant ID of the Azure Service Principal used to access the repo
|
||||
AzureServicePrincipalTenantId string `json:"azureServicePrincipalTenantId,omitempty" protobuf:"bytes,31,opt,name=azureServicePrincipalTenantId"`
|
||||
// AzureActiveDirectoryEndpoint specifies the Azure Active Directory endpoint used for Service Principal authentication. If empty will default to https://login.microsoftonline.com
|
||||
AzureActiveDirectoryEndpoint string `json:"azureActiveDirectoryEndpoint,omitempty" protobuf:"bytes,32,opt,name=azureActiveDirectoryEndpoint"`
|
||||
}
|
||||
|
||||
// IsInsecure returns true if the repository has been configured to skip server verification or set to HTTP only
|
||||
|
|
@ -134,7 +150,7 @@ func (repo *Repository) IsLFSEnabled() bool {
|
|||
|
||||
// HasCredentials returns true when the repository has been configured with any credentials
|
||||
func (repo *Repository) HasCredentials() bool {
|
||||
return repo.Username != "" || repo.Password != "" || repo.BearerToken != "" || repo.SSHPrivateKey != "" || repo.TLSClientCertData != "" || repo.GithubAppPrivateKey != "" || repo.UseAzureWorkloadIdentity
|
||||
return repo.Username != "" || repo.Password != "" || repo.BearerToken != "" || repo.SSHPrivateKey != "" || repo.TLSClientCertData != "" || repo.GithubAppPrivateKey != "" || repo.UseAzureWorkloadIdentity || repo.AzureServicePrincipalClientSecret != ""
|
||||
}
|
||||
|
||||
// CopyCredentialsFromRepo copies all credential information from source repository to receiving repository
|
||||
|
|
@ -173,6 +189,18 @@ func (repo *Repository) CopyCredentialsFromRepo(source *Repository) {
|
|||
if repo.GCPServiceAccountKey == "" {
|
||||
repo.GCPServiceAccountKey = source.GCPServiceAccountKey
|
||||
}
|
||||
if repo.AzureServicePrincipalClientId == "" {
|
||||
repo.AzureServicePrincipalClientId = source.AzureServicePrincipalClientId
|
||||
}
|
||||
if repo.AzureServicePrincipalClientSecret == "" {
|
||||
repo.AzureServicePrincipalClientSecret = source.AzureServicePrincipalClientSecret
|
||||
}
|
||||
if repo.AzureServicePrincipalTenantId == "" {
|
||||
repo.AzureServicePrincipalTenantId = source.AzureServicePrincipalTenantId
|
||||
}
|
||||
if repo.AzureActiveDirectoryEndpoint == "" {
|
||||
repo.AzureActiveDirectoryEndpoint = source.AzureActiveDirectoryEndpoint
|
||||
}
|
||||
repo.InsecureOCIForceHttp = source.InsecureOCIForceHttp
|
||||
repo.ForceHttpBasicAuth = source.ForceHttpBasicAuth
|
||||
repo.UseAzureWorkloadIdentity = source.UseAzureWorkloadIdentity
|
||||
|
|
@ -215,6 +243,18 @@ func (repo *Repository) CopyCredentialsFrom(source *RepoCreds) {
|
|||
if repo.GCPServiceAccountKey == "" {
|
||||
repo.GCPServiceAccountKey = source.GCPServiceAccountKey
|
||||
}
|
||||
if repo.AzureServicePrincipalClientId == "" {
|
||||
repo.AzureServicePrincipalClientId = source.AzureServicePrincipalClientId
|
||||
}
|
||||
if repo.AzureServicePrincipalClientSecret == "" {
|
||||
repo.AzureServicePrincipalClientSecret = source.AzureServicePrincipalClientSecret
|
||||
}
|
||||
if repo.AzureServicePrincipalTenantId == "" {
|
||||
repo.AzureServicePrincipalTenantId = source.AzureServicePrincipalTenantId
|
||||
}
|
||||
if repo.AzureActiveDirectoryEndpoint == "" {
|
||||
repo.AzureActiveDirectoryEndpoint = source.AzureActiveDirectoryEndpoint
|
||||
}
|
||||
if repo.Proxy == "" {
|
||||
repo.Proxy = source.Proxy
|
||||
}
|
||||
|
|
@ -252,6 +292,14 @@ func (repo *Repository) GetGitCreds(store git.CredsStore) git.Creds {
|
|||
if repo.UseAzureWorkloadIdentity {
|
||||
return git.NewAzureWorkloadIdentityCreds(store, workloadidentity.NewWorkloadIdentityTokenProvider())
|
||||
}
|
||||
if repo.AzureServicePrincipalClientId != "" && repo.AzureServicePrincipalClientSecret != "" && repo.AzureServicePrincipalTenantId != "" {
|
||||
creds := git.NewAzureServicePrincipalCreds(repo.AzureServicePrincipalTenantId, repo.AzureServicePrincipalClientId, repo.AzureServicePrincipalClientSecret, store).
|
||||
WithActiveDirectoryEndpoint(repo.AzureActiveDirectoryEndpoint).
|
||||
WithClientCert(repo.TLSClientCertData, repo.TLSClientCertKey).
|
||||
WithProxy(repo.Proxy).
|
||||
WithNoProxy(repo.NoProxy)
|
||||
return creds
|
||||
}
|
||||
return git.NopCreds{}
|
||||
}
|
||||
|
||||
|
|
@ -351,22 +399,25 @@ func (repo *Repository) StringForLogging() string {
|
|||
// Sanitized returns a copy of the Repository with sensitive information removed.
|
||||
func (repo *Repository) Sanitized() *Repository {
|
||||
return &Repository{
|
||||
Repo: repo.Repo,
|
||||
Type: repo.Type,
|
||||
Name: repo.Name,
|
||||
Insecure: repo.IsInsecure(),
|
||||
EnableLFS: repo.EnableLFS,
|
||||
EnableOCI: repo.EnableOCI,
|
||||
Proxy: repo.Proxy,
|
||||
NoProxy: repo.NoProxy,
|
||||
Project: repo.Project,
|
||||
ForceHttpBasicAuth: repo.ForceHttpBasicAuth,
|
||||
InheritedCreds: repo.InheritedCreds,
|
||||
GithubAppId: repo.GithubAppId,
|
||||
GithubAppInstallationId: repo.GithubAppInstallationId,
|
||||
GitHubAppEnterpriseBaseURL: repo.GitHubAppEnterpriseBaseURL,
|
||||
UseAzureWorkloadIdentity: repo.UseAzureWorkloadIdentity,
|
||||
Depth: repo.Depth,
|
||||
Repo: repo.Repo,
|
||||
Type: repo.Type,
|
||||
Name: repo.Name,
|
||||
Insecure: repo.IsInsecure(),
|
||||
EnableLFS: repo.EnableLFS,
|
||||
EnableOCI: repo.EnableOCI,
|
||||
Proxy: repo.Proxy,
|
||||
NoProxy: repo.NoProxy,
|
||||
Project: repo.Project,
|
||||
ForceHttpBasicAuth: repo.ForceHttpBasicAuth,
|
||||
InheritedCreds: repo.InheritedCreds,
|
||||
GithubAppId: repo.GithubAppId,
|
||||
GithubAppInstallationId: repo.GithubAppInstallationId,
|
||||
GitHubAppEnterpriseBaseURL: repo.GitHubAppEnterpriseBaseURL,
|
||||
UseAzureWorkloadIdentity: repo.UseAzureWorkloadIdentity,
|
||||
AzureActiveDirectoryEndpoint: repo.AzureActiveDirectoryEndpoint,
|
||||
AzureServicePrincipalClientId: repo.AzureServicePrincipalClientId,
|
||||
AzureServicePrincipalTenantId: repo.AzureServicePrincipalTenantId,
|
||||
Depth: repo.Depth,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -87,6 +87,15 @@ func TestGetGitCreds(t *testing.T) {
|
|||
},
|
||||
expected: git.NewGoogleCloudCreds("gcp-key", nil),
|
||||
},
|
||||
{
|
||||
name: "Azure Service Principal credentials",
|
||||
repo: &Repository{
|
||||
AzureServicePrincipalClientId: "client-id",
|
||||
AzureServicePrincipalClientSecret: "client-secret",
|
||||
AzureServicePrincipalTenantId: "tenant-id",
|
||||
},
|
||||
expected: git.NewAzureServicePrincipalCreds("tenant-id", "client-id", "client-secret", nil),
|
||||
},
|
||||
{
|
||||
name: "No credentials",
|
||||
repo: &Repository{},
|
||||
|
|
@ -130,30 +139,33 @@ func TestGetGitCreds_GitHubApp_InstallationNotFound(t *testing.T) {
|
|||
|
||||
func TestSanitizedRepository(t *testing.T) {
|
||||
repo := &Repository{
|
||||
Repo: "https://github.com/argoproj/argo-cd.git",
|
||||
Type: "git",
|
||||
Name: "argo-cd",
|
||||
Username: "admin",
|
||||
Password: "super-secret-password",
|
||||
SSHPrivateKey: "-----BEGIN RSA PRIVATE KEY-----",
|
||||
BearerToken: "eyJhbGciOiJIUzI1NiJ9",
|
||||
TLSClientCertData: "cert-data",
|
||||
TLSClientCertKey: "cert-key",
|
||||
GCPServiceAccountKey: "gcp-key",
|
||||
GithubAppPrivateKey: "github-app-key",
|
||||
Insecure: true,
|
||||
EnableLFS: true,
|
||||
EnableOCI: true,
|
||||
Proxy: "http://proxy:8080",
|
||||
NoProxy: "localhost",
|
||||
Project: "default",
|
||||
ForceHttpBasicAuth: true,
|
||||
InheritedCreds: true,
|
||||
GithubAppId: 12345,
|
||||
GithubAppInstallationId: 67890,
|
||||
GitHubAppEnterpriseBaseURL: "https://ghe.example.com/api/v3",
|
||||
UseAzureWorkloadIdentity: true,
|
||||
Depth: 1,
|
||||
Repo: "https://github.com/argoproj/argo-cd.git",
|
||||
Type: "git",
|
||||
Name: "argo-cd",
|
||||
Username: "admin",
|
||||
Password: "super-secret-password",
|
||||
SSHPrivateKey: "-----BEGIN RSA PRIVATE KEY-----",
|
||||
BearerToken: "eyJhbGciOiJIUzI1NiJ9",
|
||||
TLSClientCertData: "cert-data",
|
||||
TLSClientCertKey: "cert-key",
|
||||
GCPServiceAccountKey: "gcp-key",
|
||||
GithubAppPrivateKey: "github-app-key",
|
||||
Insecure: true,
|
||||
EnableLFS: true,
|
||||
EnableOCI: true,
|
||||
Proxy: "http://proxy:8080",
|
||||
NoProxy: "localhost",
|
||||
Project: "default",
|
||||
ForceHttpBasicAuth: true,
|
||||
InheritedCreds: true,
|
||||
GithubAppId: 12345,
|
||||
GithubAppInstallationId: 67890,
|
||||
GitHubAppEnterpriseBaseURL: "https://ghe.example.com/api/v3",
|
||||
UseAzureWorkloadIdentity: true,
|
||||
AzureServicePrincipalClientId: "client-id",
|
||||
AzureServicePrincipalClientSecret: "client-secret",
|
||||
AzureServicePrincipalTenantId: "tenant-id",
|
||||
Depth: 1,
|
||||
}
|
||||
|
||||
sanitized := repo.Sanitized()
|
||||
|
|
@ -174,6 +186,8 @@ func TestSanitizedRepository(t *testing.T) {
|
|||
assert.Equal(t, repo.GithubAppInstallationId, sanitized.GithubAppInstallationId)
|
||||
assert.Equal(t, repo.GitHubAppEnterpriseBaseURL, sanitized.GitHubAppEnterpriseBaseURL)
|
||||
assert.Equal(t, repo.UseAzureWorkloadIdentity, sanitized.UseAzureWorkloadIdentity)
|
||||
assert.Equal(t, repo.AzureServicePrincipalClientId, sanitized.AzureServicePrincipalClientId)
|
||||
assert.Equal(t, repo.AzureServicePrincipalTenantId, sanitized.AzureServicePrincipalTenantId)
|
||||
assert.Equal(t, repo.Depth, sanitized.Depth)
|
||||
|
||||
// Sensitive fields must be stripped
|
||||
|
|
@ -185,6 +199,7 @@ func TestSanitizedRepository(t *testing.T) {
|
|||
assert.Empty(t, sanitized.TLSClientCertKey)
|
||||
assert.Empty(t, sanitized.GCPServiceAccountKey)
|
||||
assert.Empty(t, sanitized.GithubAppPrivateKey)
|
||||
assert.Empty(t, sanitized.AzureServicePrincipalClientSecret)
|
||||
}
|
||||
|
||||
func TestSanitizedRepositoryPreservesDepthZero(t *testing.T) {
|
||||
|
|
|
|||
243
reposerver/apiclient/repository.pb.go
generated
243
reposerver/apiclient/repository.pb.go
generated
|
|
@ -578,6 +578,7 @@ type ResolveRevisionRequest struct {
|
|||
App *v1alpha1.Application `protobuf:"bytes,2,opt,name=app,proto3" json:"app,omitempty"`
|
||||
AmbiguousRevision string `protobuf:"bytes,3,opt,name=ambiguousRevision,proto3" json:"ambiguousRevision,omitempty"`
|
||||
SourceIndex int64 `protobuf:"varint,4,opt,name=sourceIndex,proto3" json:"sourceIndex,omitempty"`
|
||||
NoRevisionCache bool `protobuf:"varint,5,opt,name=noRevisionCache,proto3" json:"noRevisionCache,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
|
|
@ -644,6 +645,13 @@ func (m *ResolveRevisionRequest) GetSourceIndex() int64 {
|
|||
return 0
|
||||
}
|
||||
|
||||
func (m *ResolveRevisionRequest) GetNoRevisionCache() bool {
|
||||
if m != nil {
|
||||
return m.NoRevisionCache
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// ResolveRevisionResponse
|
||||
type ResolveRevisionResponse struct {
|
||||
// returns the resolved revision
|
||||
|
|
@ -2487,14 +2495,14 @@ func init() {
|
|||
}
|
||||
|
||||
var fileDescriptor_dd8723cfcc820480 = []byte{
|
||||
// 2441 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xdc, 0x1a, 0x4d, 0x73, 0x1c, 0x47,
|
||||
0x55, 0xfb, 0x25, 0xed, 0x3e, 0x7d, 0xad, 0xda, 0x96, 0x3c, 0x5e, 0xdb, 0x42, 0x19, 0xb0, 0xcb,
|
||||
0xb1, 0x93, 0x55, 0xd9, 0xae, 0xc4, 0xe0, 0x84, 0xa4, 0x14, 0xd9, 0x96, 0x14, 0x5b, 0xb6, 0x18,
|
||||
0x3b, 0xa1, 0x0c, 0x06, 0xaa, 0x77, 0xb6, 0xb5, 0x3b, 0xd9, 0xf9, 0x68, 0xcf, 0xf4, 0x28, 0xc8,
|
||||
0x55, 0x9c, 0xa0, 0xb8, 0xc0, 0x81, 0x53, 0x0e, 0x5c, 0xf9, 0x0d, 0x14, 0x47, 0x4e, 0x14, 0x1c,
|
||||
0x29, 0x2e, 0x5c, 0xa8, 0x82, 0xf2, 0x0f, 0xa1, 0xa8, 0xfe, 0x98, 0xcf, 0x9d, 0x5d, 0x29, 0x5e,
|
||||
0x5b, 0x06, 0x2e, 0xd2, 0x74, 0xf7, 0xeb, 0xf7, 0x5e, 0xbf, 0xaf, 0x7e, 0xef, 0xf5, 0xc2, 0x25,
|
||||
// 2447 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xdc, 0x1a, 0x4d, 0x6f, 0x1c, 0x49,
|
||||
0xd5, 0xf3, 0x65, 0xcf, 0x3c, 0x7f, 0x8d, 0x2b, 0xb1, 0xd3, 0x99, 0x24, 0xc6, 0xdb, 0x90, 0x28,
|
||||
0x9b, 0xec, 0x8e, 0x95, 0x44, 0xbb, 0x81, 0xec, 0xb2, 0x2b, 0xaf, 0x93, 0xd8, 0xde, 0xc4, 0x89,
|
||||
0xe9, 0x64, 0x17, 0x05, 0x02, 0xa8, 0xa6, 0xa7, 0x3c, 0xd3, 0x3b, 0xfd, 0x51, 0xe9, 0xae, 0xf6,
|
||||
0xe2, 0x48, 0x9c, 0x40, 0x5c, 0xe0, 0xc0, 0x69, 0x0f, 0xfc, 0x0f, 0xc4, 0x91, 0x13, 0x82, 0x0b,
|
||||
0x12, 0xe2, 0xc2, 0x05, 0x09, 0x94, 0x1f, 0x82, 0x50, 0x7d, 0xf4, 0xe7, 0xf4, 0x8c, 0xbd, 0x99,
|
||||
0xc4, 0x01, 0x2e, 0x76, 0x57, 0xd5, 0xab, 0xf7, 0x5e, 0xbd, 0xaf, 0x7a, 0xef, 0xd5, 0xc0, 0x25,
|
||||
0x9f, 0x50, 0x2f, 0x20, 0xfe, 0x01, 0xf1, 0xd7, 0xc5, 0xa7, 0xc5, 0x3c, 0xff, 0x30, 0xf5, 0xd9,
|
||||
0xa6, 0xbe, 0xc7, 0x3c, 0x04, 0xc9, 0x4c, 0xeb, 0x7e, 0xcf, 0x62, 0xfd, 0xb0, 0xd3, 0x36, 0x3d,
|
||||
0x67, 0x1d, 0xfb, 0x3d, 0x8f, 0xfa, 0xde, 0x17, 0xe2, 0xe3, 0x5d, 0xb3, 0xbb, 0x7e, 0x70, 0x63,
|
||||
|
|
@ -2545,102 +2553,102 @@ var fileDescriptor_dd8723cfcc820480 = []byte{
|
|||
0xc7, 0x08, 0x41, 0x35, 0xb0, 0x9e, 0x4b, 0x51, 0x57, 0x0c, 0xf1, 0xad, 0xbf, 0x0d, 0x4b, 0x43,
|
||||
0xd4, 0xb8, 0x52, 0x25, 0x6f, 0x1c, 0xc3, 0x9c, 0x22, 0xad, 0x87, 0xb0, 0xfc, 0x58, 0xc8, 0x22,
|
||||
0xbe, 0x5e, 0x4e, 0x22, 0x57, 0xd0, 0xb7, 0x61, 0x25, 0x4f, 0x36, 0xa0, 0x9e, 0x1b, 0x10, 0xee,
|
||||
0x6c, 0x22, 0x1e, 0x5b, 0xa4, 0x9b, 0xac, 0x0a, 0x2e, 0xea, 0x46, 0xc1, 0x8a, 0xfe, 0xbb, 0x32,
|
||||
0x6c, 0x22, 0x1e, 0x5b, 0xa4, 0x9b, 0xac, 0x0a, 0x2e, 0xea, 0x46, 0xc1, 0x8a, 0xfe, 0x97, 0x32,
|
||||
0xac, 0x18, 0x24, 0xf0, 0xec, 0x03, 0x12, 0x05, 0xcb, 0x93, 0x49, 0x77, 0x7e, 0x08, 0x15, 0x4c,
|
||||
0xa9, 0x32, 0x93, 0x9d, 0x57, 0x96, 0x50, 0x18, 0x1c, 0x2b, 0x7a, 0x07, 0x96, 0xb0, 0xd3, 0xb1,
|
||||
0x7a, 0xa1, 0x17, 0x06, 0xd1, 0xb1, 0x84, 0x51, 0x35, 0x8c, 0xe1, 0x05, 0x1e, 0x70, 0x02, 0xe1,
|
||||
0x91, 0x3b, 0x6e, 0x97, 0xfc, 0x54, 0xe4, 0x50, 0x15, 0x23, 0x3d, 0xa5, 0x9b, 0x70, 0x66, 0x48,
|
||||
0x48, 0x4a, 0xe0, 0xe9, 0xb4, 0xad, 0x94, 0x4b, 0xdb, 0x0a, 0xd9, 0x28, 0x8f, 0x60, 0x43, 0x7f,
|
||||
0x51, 0x82, 0x66, 0xe2, 0x5c, 0x0a, 0xfd, 0x79, 0x68, 0x38, 0x6a, 0x2e, 0xd0, 0x4a, 0x22, 0x66,
|
||||
0x26, 0x13, 0xd9, 0x0c, 0xae, 0x9c, 0xcf, 0xe0, 0x56, 0x60, 0x5a, 0x26, 0xd8, 0xea, 0xe8, 0x6a,
|
||||
0x94, 0x61, 0xb9, 0x9a, 0x63, 0x79, 0x15, 0x20, 0x88, 0x23, 0x9c, 0x36, 0x2d, 0x56, 0x53, 0x33,
|
||||
0x48, 0x87, 0x39, 0x79, 0xdf, 0x1b, 0x24, 0x08, 0x6d, 0xa6, 0xcd, 0x08, 0x88, 0xcc, 0x9c, 0xf0,
|
||||
0x37, 0xcf, 0x71, 0xb0, 0xdb, 0x0d, 0xb4, 0xba, 0x60, 0x39, 0x1e, 0xeb, 0x1e, 0x2c, 0xde, 0xb7,
|
||||
0xf8, 0xf9, 0xf6, 0x83, 0x93, 0x71, 0x95, 0xf7, 0xa1, 0xca, 0x89, 0x71, 0xa6, 0x3a, 0x3e, 0x76,
|
||||
0xcd, 0x3e, 0x89, 0xe4, 0x18, 0x8f, 0x79, 0x10, 0x60, 0xb8, 0x17, 0x68, 0x65, 0x31, 0x2f, 0xbe,
|
||||
0xf5, 0x3f, 0x94, 0x25, 0xa7, 0x1b, 0x94, 0x06, 0x6f, 0xbe, 0x00, 0x28, 0x4e, 0x49, 0x2a, 0xc3,
|
||||
0x29, 0x49, 0x8e, 0xe5, 0xaf, 0x93, 0x92, 0xbc, 0xa2, 0x4b, 0x4e, 0x0f, 0x61, 0x66, 0x83, 0x52,
|
||||
0xce, 0x08, 0xba, 0x06, 0x55, 0x4c, 0xa9, 0x14, 0x78, 0x2e, 0x9e, 0x2b, 0x10, 0xfe, 0x5f, 0xb1,
|
||||
0x24, 0x40, 0x5b, 0x37, 0xa1, 0x11, 0x4f, 0x1d, 0x45, 0xb6, 0x91, 0x26, 0xbb, 0x06, 0x20, 0x73,
|
||||
0xee, 0x1d, 0x77, 0xdf, 0xe3, 0x2a, 0xe5, 0x8e, 0xa0, 0xb6, 0x8a, 0x6f, 0xfd, 0x56, 0x04, 0x21,
|
||||
0x78, 0x7b, 0x07, 0x6a, 0x16, 0x23, 0x4e, 0xc4, 0xdc, 0x4a, 0x9a, 0xb9, 0x04, 0x91, 0x21, 0x81,
|
||||
0xf4, 0x3f, 0xd7, 0xe1, 0x2c, 0xd7, 0xd8, 0x23, 0xe1, 0x42, 0x1b, 0x94, 0xde, 0x26, 0x0c, 0x5b,
|
||||
0x76, 0xf0, 0xbd, 0x90, 0xf8, 0x87, 0xaf, 0xd9, 0x30, 0x7a, 0x30, 0x2d, 0x3d, 0x50, 0x45, 0xcb,
|
||||
0x57, 0x5e, 0x7e, 0x29, 0xf4, 0x49, 0xcd, 0x55, 0x79, 0x3d, 0x35, 0x57, 0x51, 0x0d, 0x54, 0x3d,
|
||||
0xa1, 0x1a, 0x68, 0x74, 0x19, 0x9c, 0x2a, 0xae, 0xa7, 0xb3, 0xc5, 0x75, 0x41, 0x69, 0x31, 0x73,
|
||||
0xdc, 0xd2, 0xa2, 0x5e, 0x58, 0x5a, 0x38, 0x85, 0x7e, 0xdc, 0x10, 0xe2, 0xfe, 0x6e, 0xda, 0x02,
|
||||
0x47, 0xda, 0xda, 0x24, 0x45, 0x06, 0xbc, 0xd6, 0x22, 0xe3, 0xb3, 0x4c, 0xd1, 0x20, 0xcb, 0xf6,
|
||||
0xf7, 0x8e, 0x77, 0xa6, 0x31, 0xe5, 0xc3, 0xff, 0x5d, 0xea, 0xfd, 0x0b, 0x91, 0x71, 0x51, 0x2f,
|
||||
0x91, 0x41, 0x7c, 0xd9, 0xf3, 0x7b, 0x88, 0x5f, 0xbb, 0x2a, 0x68, 0xf1, 0x6f, 0x74, 0x15, 0xaa,
|
||||
0x5c, 0xc8, 0x2a, 0x25, 0x3e, 0x93, 0x96, 0x27, 0xd7, 0xc4, 0x06, 0xa5, 0x8f, 0x28, 0x31, 0x0d,
|
||||
0x01, 0x84, 0x6e, 0x41, 0x23, 0x36, 0x7c, 0xe5, 0x59, 0xe7, 0xd3, 0x3b, 0x62, 0x3f, 0x89, 0xb6,
|
||||
0x25, 0xe0, 0x7c, 0x6f, 0xd7, 0xf2, 0x89, 0x29, 0x12, 0xc6, 0xda, 0xf0, 0xde, 0xdb, 0xd1, 0x62,
|
||||
0xbc, 0x37, 0x06, 0x47, 0xd7, 0x60, 0x5a, 0xf6, 0x39, 0x84, 0x07, 0xcd, 0x5e, 0x3f, 0x3b, 0x1c,
|
||||
0x4c, 0xa3, 0x5d, 0x0a, 0x50, 0xff, 0x53, 0x09, 0xde, 0x4a, 0x0c, 0x22, 0xf2, 0xa6, 0x28, 0x67,
|
||||
0x7f, 0xf3, 0x37, 0xee, 0x25, 0x58, 0x10, 0x45, 0x42, 0xd2, 0xee, 0x90, 0x9d, 0xb7, 0xdc, 0xac,
|
||||
0xfe, 0xfb, 0x12, 0x5c, 0x1c, 0x3e, 0xc7, 0x66, 0x1f, 0xfb, 0x2c, 0x56, 0xef, 0x49, 0x9c, 0x25,
|
||||
0xba, 0xf0, 0xca, 0xc9, 0x85, 0x97, 0x39, 0x5f, 0x25, 0x7b, 0x3e, 0xfd, 0x8f, 0x65, 0x98, 0x4d,
|
||||
0x19, 0x50, 0xd1, 0x85, 0xc9, 0x93, 0x41, 0x61, 0xb7, 0xa2, 0x2c, 0x14, 0x97, 0x42, 0xc3, 0x48,
|
||||
0xcd, 0xa0, 0x01, 0x00, 0xc5, 0x3e, 0x76, 0x08, 0x23, 0x3e, 0x8f, 0xe4, 0xdc, 0xe3, 0xef, 0x4d,
|
||||
0x1e, 0x5d, 0xf6, 0x22, 0x9c, 0x46, 0x0a, 0x3d, 0xcf, 0x66, 0x05, 0xe9, 0x40, 0xc5, 0x6f, 0x35,
|
||||
0x42, 0x5f, 0xc2, 0xc2, 0xbe, 0x65, 0x93, 0xbd, 0x84, 0x91, 0x69, 0xc1, 0xc8, 0xc3, 0xc9, 0x19,
|
||||
0xb9, 0x9b, 0xc6, 0x6b, 0xe4, 0xc8, 0xe8, 0x57, 0xa0, 0x99, 0xf7, 0x27, 0xce, 0xa4, 0xe5, 0xe0,
|
||||
0x5e, 0x2c, 0x2d, 0x35, 0xd2, 0x11, 0x34, 0xf3, 0xfe, 0xa3, 0xff, 0xb3, 0x0c, 0xcb, 0x31, 0xba,
|
||||
0x0d, 0xd7, 0xf5, 0x42, 0xd7, 0x14, 0xad, 0xc3, 0x42, 0x5d, 0x9c, 0x86, 0x1a, 0xb3, 0x98, 0x1d,
|
||||
0x27, 0x3e, 0x62, 0xc0, 0xef, 0x2e, 0xe6, 0x79, 0x36, 0xb3, 0xa8, 0x52, 0x70, 0x34, 0x94, 0xba,
|
||||
0x7f, 0x16, 0x5a, 0x3e, 0xe9, 0x8a, 0x48, 0x50, 0x37, 0xe2, 0x31, 0x5f, 0xe3, 0x59, 0x8d, 0x48,
|
||||
0xf1, 0xa5, 0x30, 0xe3, 0xb1, 0xb0, 0x7b, 0xcf, 0xb6, 0x89, 0xc9, 0xc5, 0x91, 0x2a, 0x02, 0x72,
|
||||
0xb3, 0xa2, 0xb8, 0x60, 0xbe, 0xe5, 0xf6, 0x54, 0x09, 0xa0, 0x46, 0x9c, 0x4f, 0xec, 0xfb, 0xf8,
|
||||
0x50, 0x65, 0xfe, 0x72, 0x80, 0x3e, 0x84, 0x8a, 0x83, 0xa9, 0xba, 0xe8, 0xae, 0x64, 0xa2, 0x43,
|
||||
0x91, 0x04, 0xda, 0xbb, 0x98, 0xca, 0x9b, 0x80, 0x6f, 0x6b, 0xbd, 0x0f, 0xf5, 0x68, 0xe2, 0x6b,
|
||||
0xa5, 0x84, 0x5f, 0xc0, 0x7c, 0x26, 0xf8, 0xa0, 0x27, 0xb0, 0x92, 0x58, 0x54, 0x9a, 0xa0, 0x4a,
|
||||
0x02, 0xdf, 0x3a, 0x92, 0x33, 0x63, 0x04, 0x02, 0xfd, 0x19, 0x2c, 0x71, 0x93, 0x11, 0x8e, 0x7f,
|
||||
0x42, 0xa5, 0xcd, 0x07, 0xd0, 0x88, 0x49, 0x16, 0xda, 0x4c, 0x0b, 0xea, 0x07, 0x51, 0x4b, 0x57,
|
||||
0xd6, 0x36, 0xf1, 0x58, 0xdf, 0x00, 0x94, 0xe6, 0x57, 0xdd, 0x40, 0x57, 0xb3, 0x49, 0xf1, 0x72,
|
||||
0xfe, 0xba, 0x11, 0xe0, 0x51, 0x4e, 0xfc, 0xf7, 0x32, 0x2c, 0x6e, 0x59, 0xa2, 0x47, 0x72, 0x42,
|
||||
0x41, 0xee, 0x0a, 0x34, 0x83, 0xb0, 0xe3, 0x78, 0xdd, 0xd0, 0x26, 0x2a, 0x29, 0x50, 0x37, 0xfd,
|
||||
0xd0, 0xfc, 0xb8, 0xe0, 0xc7, 0x85, 0x45, 0x31, 0xeb, 0xab, 0xea, 0x57, 0x7c, 0xa3, 0x0f, 0xe1,
|
||||
0xec, 0x03, 0xf2, 0xa5, 0x3a, 0xcf, 0x96, 0xed, 0x75, 0x3a, 0x96, 0xdb, 0x8b, 0x88, 0xd4, 0x04,
|
||||
0x91, 0xd1, 0x00, 0x45, 0xa9, 0xe2, 0x74, 0x71, 0xaa, 0x18, 0x57, 0xd0, 0x9b, 0x9e, 0xe3, 0x58,
|
||||
0x4c, 0x65, 0x94, 0x99, 0x39, 0xfd, 0xe7, 0x25, 0x68, 0x26, 0x92, 0x55, 0xba, 0xb9, 0x29, 0x7d,
|
||||
0x48, 0x6a, 0xe6, 0x62, 0x5a, 0x33, 0x79, 0xd0, 0x97, 0x77, 0x9f, 0xb9, 0xb4, 0xfb, 0xfc, 0xaa,
|
||||
0x0c, 0xcb, 0x5b, 0x16, 0x8b, 0x02, 0x97, 0xf5, 0xbf, 0xa6, 0xe5, 0x02, 0x9d, 0x54, 0x8f, 0xa7,
|
||||
0x93, 0x5a, 0x81, 0x4e, 0xda, 0xb0, 0x92, 0x17, 0x86, 0x52, 0xcc, 0x69, 0xa8, 0x51, 0xd1, 0x74,
|
||||
0x96, 0x7d, 0x05, 0x39, 0xd0, 0xff, 0x5d, 0x87, 0x0b, 0x9f, 0xd1, 0x2e, 0x66, 0x71, 0xcf, 0xe8,
|
||||
0xae, 0xe7, 0x8b, 0xae, 0xf3, 0xc9, 0x48, 0x31, 0xf7, 0x32, 0x58, 0x1e, 0xfb, 0x32, 0x58, 0x19,
|
||||
0xf3, 0x32, 0x58, 0x3d, 0xd6, 0xcb, 0x60, 0xed, 0xc4, 0x5e, 0x06, 0x87, 0x6b, 0xad, 0xe9, 0xc2,
|
||||
0x5a, 0xeb, 0x49, 0xa6, 0x1e, 0x99, 0x11, 0x6e, 0xf3, 0x9d, 0xb4, 0xdb, 0x8c, 0xd5, 0xce, 0xd8,
|
||||
0x27, 0x8d, 0xdc, 0x83, 0x5a, 0xfd, 0xc8, 0x07, 0xb5, 0xc6, 0xf0, 0x83, 0x5a, 0xf1, 0x9b, 0x0c,
|
||||
0x8c, 0x7c, 0x93, 0xb9, 0x04, 0x0b, 0xc1, 0xa1, 0x6b, 0x92, 0x6e, 0xdc, 0x49, 0x9c, 0x95, 0xc7,
|
||||
0xce, 0xce, 0x66, 0x3c, 0x62, 0x2e, 0xe7, 0x11, 0xb1, 0xa5, 0xce, 0xa7, 0x2c, 0xb5, 0xc8, 0x4f,
|
||||
0x16, 0x46, 0x96, 0xb9, 0xb9, 0xe7, 0x92, 0xc5, 0xa2, 0xe7, 0x12, 0x34, 0x80, 0x66, 0xc4, 0x55,
|
||||
0xac, 0x80, 0xa6, 0x50, 0xc0, 0xc7, 0xc7, 0x57, 0xc0, 0xa3, 0x1c, 0x06, 0xa9, 0x86, 0x21, 0xc4,
|
||||
0xff, 0x35, 0x95, 0x5d, 0xeb, 0xd7, 0x25, 0x58, 0x2e, 0x64, 0xfa, 0xcd, 0x14, 0x9a, 0x9f, 0xc3,
|
||||
0xea, 0x28, 0x01, 0xab, 0xc0, 0xa5, 0xc1, 0x8c, 0xd9, 0xc7, 0x6e, 0x4f, 0xb4, 0x44, 0x45, 0xe7,
|
||||
0x43, 0x0d, 0xc7, 0x55, 0x46, 0xd7, 0xbf, 0x9a, 0x83, 0xa5, 0xa4, 0xe2, 0xe1, 0x7f, 0x2d, 0x93,
|
||||
0xa0, 0x87, 0xd0, 0x8c, 0x9e, 0xd6, 0xa2, 0x26, 0x36, 0x1a, 0xf7, 0x6e, 0xd4, 0x3a, 0x5f, 0xbc,
|
||||
0x28, 0x59, 0xd3, 0xa7, 0x90, 0x09, 0x67, 0xf3, 0x08, 0x93, 0x27, 0xaa, 0x6f, 0x8d, 0xc1, 0x1c,
|
||||
0x43, 0x1d, 0x45, 0xe2, 0x72, 0x09, 0x3d, 0x81, 0x85, 0xec, 0x43, 0x0a, 0xca, 0xa4, 0x80, 0x85,
|
||||
0x6f, 0x3b, 0x2d, 0x7d, 0x1c, 0x48, 0xcc, 0xff, 0x53, 0x6e, 0x95, 0x99, 0x37, 0x03, 0xa4, 0x67,
|
||||
0xbb, 0x21, 0x45, 0xaf, 0x2e, 0xad, 0x6f, 0x8e, 0x85, 0x89, 0xb1, 0x7f, 0x00, 0xf5, 0xa8, 0x8f,
|
||||
0x9e, 0x15, 0x73, 0xae, 0xbb, 0xde, 0x6a, 0x66, 0xf1, 0xed, 0x07, 0xfa, 0x14, 0xfa, 0x08, 0x66,
|
||||
0x39, 0xd8, 0xc3, 0xcd, 0x9d, 0xc7, 0xb8, 0xf7, 0x52, 0xfb, 0xeb, 0x51, 0x9f, 0x79, 0x78, 0x73,
|
||||
0xaa, 0xfb, 0xdc, 0x3a, 0x55, 0xd0, 0xf1, 0xd5, 0xa7, 0xd0, 0xc7, 0x92, 0xfe, 0x9e, 0xfa, 0x69,
|
||||
0xc4, 0x4a, 0x5b, 0xfe, 0x12, 0xa7, 0x1d, 0xfd, 0x12, 0xa7, 0x7d, 0xc7, 0xa1, 0xec, 0xb0, 0x55,
|
||||
0xd0, 0x92, 0x55, 0x08, 0x9e, 0xc2, 0xfc, 0x16, 0x61, 0x49, 0x07, 0x05, 0x5d, 0x3c, 0x56, 0x9f,
|
||||
0xa9, 0xa5, 0xe7, 0xc1, 0x86, 0x9b, 0x30, 0xfa, 0x14, 0xfa, 0xaa, 0x04, 0xa7, 0xb6, 0x08, 0xcb,
|
||||
0xf7, 0x24, 0xd0, 0xbb, 0xc5, 0x44, 0x46, 0xf4, 0x2e, 0x5a, 0x0f, 0x26, 0xf5, 0xe9, 0x2c, 0x5a,
|
||||
0x7d, 0x0a, 0xfd, 0xa6, 0x04, 0x0b, 0x5b, 0x84, 0xeb, 0x2d, 0xe6, 0xe9, 0xda, 0x78, 0x9e, 0x0a,
|
||||
0xfa, 0x10, 0xad, 0x09, 0xfb, 0x7f, 0x29, 0xea, 0xfa, 0x14, 0xfa, 0x6d, 0x09, 0xce, 0xa4, 0x64,
|
||||
0x95, 0xa6, 0xf7, 0x32, 0xbc, 0x7d, 0x3a, 0xe1, 0x8f, 0x70, 0x52, 0x28, 0xf5, 0x29, 0xb4, 0x27,
|
||||
0xcc, 0x24, 0x29, 0x73, 0xd0, 0x85, 0xc2, 0x7a, 0x26, 0xa6, 0xbe, 0x3a, 0x6a, 0x39, 0x36, 0x8d,
|
||||
0x4f, 0x61, 0x76, 0x8b, 0xb0, 0x28, 0xdf, 0xce, 0x1a, 0x7f, 0xae, 0x14, 0xca, 0x46, 0x9f, 0x7c,
|
||||
0x8a, 0x2e, 0x8c, 0x78, 0x49, 0xe2, 0x4a, 0xe5, 0x94, 0xd9, 0xf0, 0x53, 0x98, 0x7c, 0x67, 0x8d,
|
||||
0xb8, 0x38, 0x25, 0xd5, 0xa7, 0xd0, 0x33, 0x58, 0x29, 0x8e, 0xfe, 0xe8, 0xed, 0x63, 0x5f, 0xc1,
|
||||
0xad, 0x2b, 0xc7, 0x01, 0x8d, 0x48, 0x7e, 0xb2, 0xf1, 0x97, 0x17, 0xab, 0xa5, 0xbf, 0xbe, 0x58,
|
||||
0x2d, 0xfd, 0xeb, 0xc5, 0x6a, 0xe9, 0x07, 0x37, 0x8e, 0xf8, 0xb1, 0x5e, 0xea, 0xf7, 0x7f, 0x98,
|
||||
0x5a, 0xa6, 0x6d, 0x11, 0x97, 0x75, 0xa6, 0x45, 0x08, 0xb8, 0xf1, 0x9f, 0x00, 0x00, 0x00, 0xff,
|
||||
0xff, 0xaa, 0x40, 0x0c, 0xdc, 0x1e, 0x28, 0x00, 0x00,
|
||||
0x91, 0x3b, 0x6e, 0x97, 0xfc, 0x54, 0xe4, 0x50, 0x15, 0x23, 0x3d, 0x55, 0x74, 0xc7, 0xd4, 0x0a,
|
||||
0xef, 0x18, 0xdd, 0x84, 0x33, 0x43, 0xe2, 0x54, 0xaa, 0x49, 0x27, 0x78, 0xa5, 0x5c, 0x82, 0x57,
|
||||
0xc8, 0x70, 0x79, 0x04, 0xc3, 0xfa, 0x8b, 0x12, 0x34, 0x13, 0x37, 0x54, 0xe8, 0xcf, 0x43, 0xc3,
|
||||
0x51, 0x73, 0x81, 0x56, 0x12, 0xd1, 0x35, 0x99, 0xc8, 0xe6, 0x7a, 0xe5, 0x7c, 0xae, 0xb7, 0x02,
|
||||
0xd3, 0x32, 0x15, 0x57, 0x42, 0x52, 0xa3, 0x0c, 0xcb, 0xd5, 0x1c, 0xcb, 0xab, 0x00, 0x41, 0x1c,
|
||||
0x0b, 0xb5, 0x69, 0xb1, 0x9a, 0x9a, 0x41, 0x3a, 0xcc, 0xc9, 0xcc, 0xc0, 0x20, 0x41, 0x68, 0x33,
|
||||
0x6d, 0x46, 0x40, 0x64, 0xe6, 0x84, 0x67, 0x7a, 0x8e, 0x83, 0xdd, 0x6e, 0xa0, 0xd5, 0x05, 0xcb,
|
||||
0xf1, 0x58, 0xf7, 0x60, 0xf1, 0xbe, 0xc5, 0xcf, 0xb7, 0x1f, 0x9c, 0x8c, 0x53, 0xbd, 0x0f, 0x55,
|
||||
0x4e, 0x8c, 0x33, 0xd5, 0xf1, 0xb1, 0x6b, 0xf6, 0x49, 0x24, 0xc7, 0x78, 0xcc, 0xc3, 0x05, 0xc3,
|
||||
0xbd, 0x40, 0x2b, 0x8b, 0x79, 0xf1, 0xad, 0xff, 0xbe, 0x2c, 0x39, 0xdd, 0xa0, 0x34, 0x78, 0xf3,
|
||||
0xa5, 0x42, 0x71, 0xf2, 0x52, 0x19, 0x4e, 0x5e, 0x72, 0x2c, 0x7f, 0x9d, 0xe4, 0xe5, 0x15, 0x5d,
|
||||
0x87, 0x7a, 0x08, 0x33, 0x1b, 0x94, 0x72, 0x46, 0xd0, 0x35, 0xa8, 0x62, 0x4a, 0xa5, 0xc0, 0x73,
|
||||
0x91, 0x5f, 0x81, 0xf0, 0xff, 0x8a, 0x25, 0x01, 0xda, 0xba, 0x09, 0x8d, 0x78, 0xea, 0x28, 0xb2,
|
||||
0x8d, 0x34, 0xd9, 0x35, 0x00, 0x99, 0x9d, 0xef, 0xb8, 0xfb, 0x1e, 0x57, 0x29, 0x77, 0x04, 0xb5,
|
||||
0x55, 0x7c, 0xeb, 0xb7, 0x22, 0x08, 0xc1, 0xdb, 0x3b, 0x50, 0xb3, 0x18, 0x71, 0x22, 0xe6, 0x56,
|
||||
0xd2, 0xcc, 0x25, 0x88, 0x0c, 0x09, 0xa4, 0xff, 0xa9, 0x0e, 0x67, 0xb9, 0xc6, 0x1e, 0x09, 0x17,
|
||||
0xda, 0xa0, 0xf4, 0x36, 0x61, 0xd8, 0xb2, 0x83, 0xef, 0x85, 0xc4, 0x3f, 0x7c, 0xcd, 0x86, 0xd1,
|
||||
0x83, 0x69, 0xe9, 0x81, 0x2a, 0xae, 0xbe, 0xf2, 0x42, 0x4d, 0xa1, 0x4f, 0xaa, 0xb3, 0xca, 0xeb,
|
||||
0xa9, 0xce, 0x8a, 0xaa, 0xa5, 0xea, 0x09, 0x55, 0x4b, 0xa3, 0x0b, 0xe6, 0x54, 0x19, 0x3e, 0x9d,
|
||||
0x2d, 0xc3, 0x0b, 0x2e, 0x88, 0x99, 0xe3, 0x16, 0x21, 0xf5, 0xc2, 0x22, 0xc4, 0x29, 0xf4, 0xe3,
|
||||
0x86, 0x10, 0xf7, 0x77, 0xd3, 0x16, 0x38, 0xd2, 0xd6, 0x26, 0x29, 0x47, 0xe0, 0xb5, 0x96, 0x23,
|
||||
0x9f, 0x65, 0xca, 0x0b, 0x59, 0xe0, 0xbf, 0x77, 0xbc, 0x33, 0x8d, 0x29, 0x34, 0xfe, 0xef, 0x92,
|
||||
0xf4, 0x5f, 0x88, 0xdc, 0x8c, 0x7a, 0x89, 0x0c, 0xe2, 0xcb, 0x9e, 0xdf, 0x43, 0xfc, 0xda, 0x55,
|
||||
0x41, 0x8b, 0x7f, 0xa3, 0xab, 0x50, 0xe5, 0x42, 0x56, 0xc9, 0xf3, 0x99, 0xb4, 0x3c, 0xb9, 0x26,
|
||||
0x36, 0x28, 0x7d, 0x44, 0x89, 0x69, 0x08, 0x20, 0x74, 0x0b, 0x1a, 0xb1, 0xe1, 0x2b, 0xcf, 0x3a,
|
||||
0x9f, 0xde, 0x11, 0xfb, 0x49, 0xb4, 0x2d, 0x01, 0xe7, 0x7b, 0xbb, 0x96, 0x4f, 0x4c, 0x91, 0x5a,
|
||||
0xd6, 0x86, 0xf7, 0xde, 0x8e, 0x16, 0xe3, 0xbd, 0x31, 0x38, 0xba, 0x06, 0xd3, 0xb2, 0x23, 0x22,
|
||||
0x3c, 0x68, 0xf6, 0xfa, 0xd9, 0xe1, 0x60, 0x1a, 0xed, 0x52, 0x80, 0xfa, 0x1f, 0x4b, 0xf0, 0x56,
|
||||
0x62, 0x10, 0x91, 0x37, 0x45, 0xd9, 0xfd, 0x9b, 0xbf, 0x71, 0x2f, 0xc1, 0x82, 0x28, 0x27, 0x92,
|
||||
0xc6, 0x88, 0xec, 0xd1, 0xe5, 0x66, 0xf5, 0xdf, 0x95, 0xe0, 0xe2, 0xf0, 0x39, 0x36, 0xfb, 0xd8,
|
||||
0x67, 0xb1, 0x7a, 0x4f, 0xe2, 0x2c, 0xd1, 0x85, 0x57, 0x4e, 0x2e, 0xbc, 0xcc, 0xf9, 0x2a, 0xd9,
|
||||
0xf3, 0xe9, 0x7f, 0x28, 0xc3, 0x6c, 0xca, 0x80, 0x8a, 0x2e, 0x4c, 0x9e, 0x0c, 0x0a, 0xbb, 0x15,
|
||||
0x05, 0xa4, 0xb8, 0x14, 0x1a, 0x46, 0x6a, 0x06, 0x0d, 0x00, 0x28, 0xf6, 0xb1, 0x43, 0x18, 0xf1,
|
||||
0x79, 0x24, 0xe7, 0x1e, 0x7f, 0x6f, 0xf2, 0xe8, 0xb2, 0x17, 0xe1, 0x34, 0x52, 0xe8, 0x79, 0x36,
|
||||
0x2b, 0x48, 0x07, 0x2a, 0x7e, 0xab, 0x11, 0xfa, 0x12, 0x16, 0xf6, 0x2d, 0x9b, 0xec, 0x25, 0x8c,
|
||||
0x4c, 0x0b, 0x46, 0x1e, 0x4e, 0xce, 0xc8, 0xdd, 0x34, 0x5e, 0x23, 0x47, 0x46, 0xbf, 0x02, 0xcd,
|
||||
0xbc, 0x3f, 0x71, 0x26, 0x2d, 0x07, 0xf7, 0x62, 0x69, 0xa9, 0x91, 0x8e, 0xa0, 0x99, 0xf7, 0x1f,
|
||||
0xfd, 0x9f, 0x65, 0x58, 0x8e, 0xd1, 0x6d, 0xb8, 0xae, 0x17, 0xba, 0xa6, 0x68, 0x32, 0x16, 0xea,
|
||||
0xe2, 0x34, 0xd4, 0x98, 0xc5, 0xec, 0x38, 0xf1, 0x11, 0x03, 0x7e, 0x77, 0x31, 0xcf, 0xb3, 0x99,
|
||||
0x45, 0x95, 0x82, 0xa3, 0xa1, 0xd4, 0xfd, 0xb3, 0xd0, 0xf2, 0x49, 0x57, 0x44, 0x82, 0xba, 0x11,
|
||||
0x8f, 0xf9, 0x1a, 0xcf, 0x6a, 0x44, 0x8a, 0x2f, 0x85, 0x19, 0x8f, 0x85, 0xdd, 0x7b, 0xb6, 0x4d,
|
||||
0x4c, 0x2e, 0x8e, 0x54, 0x11, 0x90, 0x9b, 0x15, 0xc5, 0x05, 0xf3, 0x2d, 0xb7, 0xa7, 0x4a, 0x00,
|
||||
0x35, 0xe2, 0x7c, 0x62, 0xdf, 0xc7, 0x87, 0x2a, 0xf3, 0x97, 0x03, 0xf4, 0x21, 0x54, 0x1c, 0x4c,
|
||||
0xd5, 0x45, 0x77, 0x25, 0x13, 0x1d, 0x8a, 0x24, 0xd0, 0xde, 0xc5, 0x54, 0xde, 0x04, 0x7c, 0x5b,
|
||||
0xeb, 0x7d, 0xa8, 0x47, 0x13, 0x5f, 0x2b, 0x25, 0xfc, 0x02, 0xe6, 0x33, 0xc1, 0x07, 0x3d, 0x81,
|
||||
0x95, 0xc4, 0xa2, 0xd2, 0x04, 0x55, 0x12, 0xf8, 0xd6, 0x91, 0x9c, 0x19, 0x23, 0x10, 0xe8, 0xcf,
|
||||
0x60, 0x89, 0x9b, 0x8c, 0x70, 0xfc, 0x13, 0x2a, 0x6d, 0x3e, 0x80, 0x46, 0x4c, 0xb2, 0xd0, 0x66,
|
||||
0x5a, 0x50, 0x3f, 0x88, 0x9a, 0xbf, 0xb2, 0xb6, 0x89, 0xc7, 0xfa, 0x06, 0xa0, 0x34, 0xbf, 0xea,
|
||||
0x06, 0xba, 0x9a, 0x4d, 0x8a, 0x97, 0xf3, 0xd7, 0x8d, 0x00, 0x8f, 0x72, 0xe2, 0xbf, 0x97, 0x61,
|
||||
0x71, 0xcb, 0x12, 0xdd, 0x94, 0x13, 0x0a, 0x72, 0x57, 0xa0, 0x19, 0x84, 0x1d, 0xc7, 0xeb, 0x86,
|
||||
0x36, 0x51, 0x49, 0x81, 0xba, 0xe9, 0x87, 0xe6, 0xc7, 0x05, 0x3f, 0x2e, 0x2c, 0x8a, 0x59, 0x5f,
|
||||
0x55, 0xbf, 0xe2, 0x1b, 0x7d, 0x08, 0x67, 0x1f, 0x90, 0x2f, 0xd5, 0x79, 0xb6, 0x6c, 0xaf, 0xd3,
|
||||
0xb1, 0xdc, 0x5e, 0x44, 0x44, 0xf6, 0x05, 0x46, 0x03, 0x14, 0xa5, 0x8a, 0xd3, 0xc5, 0xa9, 0x62,
|
||||
0x5c, 0x41, 0x6f, 0x7a, 0x8e, 0x63, 0x31, 0x95, 0x51, 0x66, 0xe6, 0xf4, 0x9f, 0x97, 0xa0, 0x99,
|
||||
0x48, 0x56, 0xe9, 0xe6, 0xa6, 0xf4, 0x21, 0xa9, 0x99, 0x8b, 0x69, 0xcd, 0xe4, 0x41, 0x5f, 0xde,
|
||||
0x7d, 0xe6, 0xd2, 0xee, 0xf3, 0xab, 0x32, 0x2c, 0x6f, 0x59, 0x2c, 0x0a, 0x5c, 0xd6, 0xff, 0x9a,
|
||||
0x96, 0x0b, 0x74, 0x52, 0x3d, 0x9e, 0x4e, 0x6a, 0x05, 0x3a, 0x69, 0xc3, 0x4a, 0x5e, 0x18, 0x4a,
|
||||
0x31, 0xa7, 0xa1, 0x46, 0x45, 0x7b, 0x5a, 0xf6, 0x15, 0xe4, 0x40, 0xff, 0x77, 0x1d, 0x2e, 0x7c,
|
||||
0x46, 0xbb, 0x98, 0xc5, 0x3d, 0xa3, 0xbb, 0x9e, 0x2f, 0xfa, 0xd3, 0x27, 0x23, 0xc5, 0xdc, 0x1b,
|
||||
0x62, 0x79, 0xec, 0x1b, 0x62, 0x65, 0xcc, 0x1b, 0x62, 0xf5, 0x58, 0x6f, 0x88, 0xb5, 0x13, 0x7b,
|
||||
0x43, 0x1c, 0xae, 0xb5, 0xa6, 0x0b, 0x6b, 0xad, 0x27, 0x99, 0x7a, 0x64, 0x46, 0xb8, 0xcd, 0x77,
|
||||
0xd2, 0x6e, 0x33, 0x56, 0x3b, 0x63, 0x1f, 0x3f, 0x72, 0x4f, 0x6f, 0xf5, 0x23, 0x9f, 0xde, 0x1a,
|
||||
0xc3, 0x4f, 0x6f, 0xc5, 0xaf, 0x37, 0x30, 0xf2, 0xf5, 0xe6, 0x12, 0x2c, 0x04, 0x87, 0xae, 0x49,
|
||||
0xba, 0x71, 0x27, 0x71, 0x56, 0x1e, 0x3b, 0x3b, 0x9b, 0xf1, 0x88, 0xb9, 0x9c, 0x47, 0xc4, 0x96,
|
||||
0x3a, 0x9f, 0xb2, 0xd4, 0x22, 0x3f, 0x59, 0x18, 0x59, 0xe6, 0xe6, 0x1e, 0x56, 0x16, 0x8b, 0x1e,
|
||||
0x56, 0xd0, 0x00, 0x9a, 0x11, 0x57, 0xb1, 0x02, 0x9a, 0x42, 0x01, 0x1f, 0x1f, 0x5f, 0x01, 0x8f,
|
||||
0x72, 0x18, 0xa4, 0x1a, 0x86, 0x10, 0xff, 0xd7, 0x54, 0x76, 0xad, 0x5f, 0x97, 0x60, 0xb9, 0x90,
|
||||
0xe9, 0x37, 0x53, 0x68, 0x7e, 0x0e, 0xab, 0xa3, 0x04, 0xac, 0x02, 0x97, 0x06, 0x33, 0x66, 0x1f,
|
||||
0xbb, 0x3d, 0xd1, 0x12, 0x15, 0x9d, 0x0f, 0x35, 0x1c, 0x57, 0x19, 0x5d, 0xff, 0x6a, 0x0e, 0x96,
|
||||
0x92, 0x8a, 0x87, 0xff, 0xb5, 0x4c, 0x82, 0x1e, 0x42, 0x33, 0x7a, 0x84, 0x8b, 0x9a, 0xd8, 0x68,
|
||||
0xdc, 0x0b, 0x53, 0xeb, 0x7c, 0xf1, 0xa2, 0x64, 0x4d, 0x9f, 0x42, 0x26, 0x9c, 0xcd, 0x23, 0x4c,
|
||||
0x1e, 0xb3, 0xbe, 0x35, 0x06, 0x73, 0x0c, 0x75, 0x14, 0x89, 0xcb, 0x25, 0xf4, 0x04, 0x16, 0xb2,
|
||||
0x4f, 0x2e, 0x28, 0x93, 0x02, 0x16, 0xbe, 0x02, 0xb5, 0xf4, 0x71, 0x20, 0x31, 0xff, 0x4f, 0xb9,
|
||||
0x55, 0x66, 0xde, 0x0c, 0x90, 0x9e, 0xed, 0x86, 0x14, 0xbd, 0xcf, 0xb4, 0xbe, 0x39, 0x16, 0x26,
|
||||
0xc6, 0xfe, 0x01, 0xd4, 0xa3, 0x3e, 0x7a, 0x56, 0xcc, 0xb9, 0xee, 0x7a, 0xab, 0x99, 0xc5, 0xb7,
|
||||
0x1f, 0xe8, 0x53, 0xe8, 0x23, 0x98, 0xe5, 0x60, 0x0f, 0x37, 0x77, 0x1e, 0xe3, 0xde, 0x4b, 0xed,
|
||||
0xaf, 0x47, 0x7d, 0xe6, 0xe1, 0xcd, 0xa9, 0xee, 0x73, 0xeb, 0x54, 0x41, 0xc7, 0x57, 0x9f, 0x42,
|
||||
0x1f, 0x4b, 0xfa, 0x7b, 0xea, 0x47, 0x14, 0x2b, 0x6d, 0xf9, 0x9b, 0x9d, 0x76, 0xf4, 0x9b, 0x9d,
|
||||
0xf6, 0x1d, 0x87, 0xb2, 0xc3, 0x56, 0x41, 0x4b, 0x56, 0x21, 0x78, 0x0a, 0xf3, 0x5b, 0x84, 0x25,
|
||||
0x1d, 0x14, 0x74, 0xf1, 0x58, 0x7d, 0xa6, 0x96, 0x9e, 0x07, 0x1b, 0x6e, 0xc2, 0xe8, 0x53, 0xe8,
|
||||
0xab, 0x12, 0x9c, 0xda, 0x22, 0x2c, 0xdf, 0x93, 0x40, 0xef, 0x16, 0x13, 0x19, 0xd1, 0xbb, 0x68,
|
||||
0x3d, 0x98, 0xd4, 0xa7, 0xb3, 0x68, 0xf5, 0x29, 0xf4, 0x9b, 0x12, 0x2c, 0x6c, 0x11, 0xae, 0xb7,
|
||||
0x98, 0xa7, 0x6b, 0xe3, 0x79, 0x2a, 0xe8, 0x43, 0xb4, 0x26, 0xec, 0xff, 0xa5, 0xa8, 0xeb, 0x53,
|
||||
0xe8, 0xb7, 0x25, 0x38, 0x93, 0x92, 0x55, 0x9a, 0xde, 0xcb, 0xf0, 0xf6, 0xe9, 0x84, 0x3f, 0xd7,
|
||||
0x49, 0xa1, 0xd4, 0xa7, 0xd0, 0x9e, 0x30, 0x93, 0xa4, 0xcc, 0x41, 0x17, 0x0a, 0xeb, 0x99, 0x98,
|
||||
0xfa, 0xea, 0xa8, 0xe5, 0xd8, 0x34, 0x3e, 0x85, 0xd9, 0x2d, 0xc2, 0xa2, 0x7c, 0x3b, 0x6b, 0xfc,
|
||||
0xb9, 0x52, 0x28, 0x1b, 0x7d, 0xf2, 0x29, 0xba, 0x30, 0xe2, 0x25, 0x89, 0x2b, 0x95, 0x53, 0x66,
|
||||
0xc3, 0x4f, 0x61, 0xf2, 0x9d, 0x35, 0xe2, 0xe2, 0x94, 0x54, 0x9f, 0x42, 0xcf, 0x60, 0xa5, 0x38,
|
||||
0xfa, 0xa3, 0xb7, 0x8f, 0x7d, 0x05, 0xb7, 0xae, 0x1c, 0x07, 0x34, 0x22, 0xf9, 0xc9, 0xc6, 0x9f,
|
||||
0x5f, 0xac, 0x96, 0xfe, 0xfa, 0x62, 0xb5, 0xf4, 0xaf, 0x17, 0xab, 0xa5, 0x1f, 0xdc, 0x38, 0xe2,
|
||||
0x67, 0x7d, 0xa9, 0x5f, 0x0a, 0x62, 0x6a, 0x99, 0xb6, 0x45, 0x5c, 0xd6, 0x99, 0x16, 0x21, 0xe0,
|
||||
0xc6, 0x7f, 0x02, 0x00, 0x00, 0xff, 0xff, 0x3f, 0x5c, 0xe7, 0x38, 0x48, 0x28, 0x00, 0x00,
|
||||
}
|
||||
|
||||
// Reference imports to suppress errors if they are not otherwise used.
|
||||
|
|
@ -3912,6 +3920,16 @@ func (m *ResolveRevisionRequest) MarshalToSizedBuffer(dAtA []byte) (int, error)
|
|||
i -= len(m.XXX_unrecognized)
|
||||
copy(dAtA[i:], m.XXX_unrecognized)
|
||||
}
|
||||
if m.NoRevisionCache {
|
||||
i--
|
||||
if m.NoRevisionCache {
|
||||
dAtA[i] = 1
|
||||
} else {
|
||||
dAtA[i] = 0
|
||||
}
|
||||
i--
|
||||
dAtA[i] = 0x28
|
||||
}
|
||||
if m.SourceIndex != 0 {
|
||||
i = encodeVarintRepository(dAtA, i, uint64(m.SourceIndex))
|
||||
i--
|
||||
|
|
@ -5891,6 +5909,9 @@ func (m *ResolveRevisionRequest) Size() (n int) {
|
|||
if m.SourceIndex != 0 {
|
||||
n += 1 + sovRepository(uint64(m.SourceIndex))
|
||||
}
|
||||
if m.NoRevisionCache {
|
||||
n += 2
|
||||
}
|
||||
if m.XXX_unrecognized != nil {
|
||||
n += len(m.XXX_unrecognized)
|
||||
}
|
||||
|
|
@ -8280,6 +8301,26 @@ func (m *ResolveRevisionRequest) Unmarshal(dAtA []byte) error {
|
|||
break
|
||||
}
|
||||
}
|
||||
case 5:
|
||||
if wireType != 0 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field NoRevisionCache", wireType)
|
||||
}
|
||||
var v int
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowRepository
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
v |= int(b&0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
m.NoRevisionCache = bool(v != 0)
|
||||
default:
|
||||
iNdEx = preIndex
|
||||
skippy, err := skipRepository(dAtA[iNdEx:])
|
||||
|
|
|
|||
|
|
@ -3081,15 +3081,10 @@ func (s *Service) ResolveRevision(ctx context.Context, q *apiclient.ResolveRevis
|
|||
AmbiguousRevision: fmt.Sprintf("%v (%v)", ambiguousRevision, revision),
|
||||
}, nil
|
||||
}
|
||||
gitClient, err := git.NewClient(repo.Repo, repo.GetGitCreds(s.gitCredsStore), repo.IsInsecure(), repo.IsLFSEnabled(), repo.Proxy, repo.NoProxy)
|
||||
_, revision, err := s.newClientResolveRevision(repo, ambiguousRevision, git.WithCache(s.cache, !q.NoRevisionCache))
|
||||
if err != nil {
|
||||
return &apiclient.ResolveRevisionResponse{Revision: "", AmbiguousRevision: ""}, err
|
||||
}
|
||||
revision, err := gitClient.LsRemote(ambiguousRevision)
|
||||
if err != nil {
|
||||
s.metricsServer.IncGitLsRemoteFail(gitClient.Root(), revision)
|
||||
return &apiclient.ResolveRevisionResponse{Revision: "", AmbiguousRevision: ""}, err
|
||||
}
|
||||
return &apiclient.ResolveRevisionResponse{
|
||||
Revision: revision,
|
||||
AmbiguousRevision: fmt.Sprintf("%s (%s)", ambiguousRevision, revision),
|
||||
|
|
|
|||
|
|
@ -80,6 +80,7 @@ message ResolveRevisionRequest {
|
|||
github.com.argoproj.argo_cd.v3.pkg.apis.application.v1alpha1.Application app = 2;
|
||||
string ambiguousRevision = 3;
|
||||
int64 sourceIndex = 4;
|
||||
bool noRevisionCache = 5;
|
||||
}
|
||||
|
||||
// ResolveRevisionResponse
|
||||
|
|
|
|||
|
|
@ -2996,7 +2996,12 @@ func Test_getHelmDependencyRepos(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestResolveRevision(t *testing.T) {
|
||||
service := newService(t, ".")
|
||||
expectedRevision := "03b17e0233e64787ffb5fcf65c740cc2a20822ba"
|
||||
service, _, _ := newServiceWithOpt(t, func(gitClient *gitmocks.Client, _ *helmmocks.Client, _ *ocimocks.Client, paths *iomocks.TempPaths) {
|
||||
gitClient.EXPECT().LsRemote("v2.2.2").Return(expectedRevision, nil)
|
||||
gitClient.EXPECT().Root().Return(".")
|
||||
paths.EXPECT().GetPath(mock.Anything).Return(".", nil)
|
||||
}, ".")
|
||||
repo := &v1alpha1.Repository{Repo: "https://github.com/argoproj/argo-cd"}
|
||||
app := &v1alpha1.Application{Spec: v1alpha1.ApplicationSpec{Source: &v1alpha1.ApplicationSource{}}}
|
||||
resolveRevisionResponse, err := service.ResolveRevision(t.Context(), &apiclient.ResolveRevisionRequest{
|
||||
|
|
@ -3006,8 +3011,8 @@ func TestResolveRevision(t *testing.T) {
|
|||
})
|
||||
|
||||
expectedResolveRevisionResponse := &apiclient.ResolveRevisionResponse{
|
||||
Revision: "03b17e0233e64787ffb5fcf65c740cc2a20822ba",
|
||||
AmbiguousRevision: "v2.2.2 (03b17e0233e64787ffb5fcf65c740cc2a20822ba)",
|
||||
Revision: expectedRevision,
|
||||
AmbiguousRevision: fmt.Sprintf("v2.2.2 (%s)", expectedRevision),
|
||||
}
|
||||
|
||||
assert.NotNil(t, resolveRevisionResponse.Revision)
|
||||
|
|
@ -3016,7 +3021,11 @@ func TestResolveRevision(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestResolveRevisionNegativeScenarios(t *testing.T) {
|
||||
service := newService(t, ".")
|
||||
service, _, _ := newServiceWithOpt(t, func(gitClient *gitmocks.Client, _ *helmmocks.Client, _ *ocimocks.Client, paths *iomocks.TempPaths) {
|
||||
gitClient.EXPECT().LsRemote("v2.a.2").Return("", fmt.Errorf("unable to resolve '%s' to a commit SHA", "v2.a.2"))
|
||||
gitClient.EXPECT().Root().Return(".")
|
||||
paths.EXPECT().GetPath(mock.Anything).Return(".", nil)
|
||||
}, ".")
|
||||
repo := &v1alpha1.Repository{Repo: "https://github.com/argoproj/argo-cd"}
|
||||
app := &v1alpha1.Application{Spec: v1alpha1.ApplicationSpec{Source: &v1alpha1.ApplicationSource{}}}
|
||||
resolveRevisionResponse, err := service.ResolveRevision(t.Context(), &apiclient.ResolveRevisionRequest{
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import (
|
|||
"fmt"
|
||||
"regexp"
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
|
|
@ -19,6 +20,7 @@ import (
|
|||
"github.com/argoproj/argo-cd/v3/server/rbacpolicy"
|
||||
"github.com/argoproj/argo-cd/v3/util/password"
|
||||
"github.com/argoproj/argo-cd/v3/util/rbac"
|
||||
"github.com/argoproj/argo-cd/v3/util/security"
|
||||
"github.com/argoproj/argo-cd/v3/util/session"
|
||||
"github.com/argoproj/argo-cd/v3/util/settings"
|
||||
)
|
||||
|
|
@ -28,11 +30,12 @@ type Server struct {
|
|||
sessionMgr *session.SessionManager
|
||||
settingsMgr *settings.SettingsManager
|
||||
enf *rbac.Enforcer
|
||||
namespace string
|
||||
}
|
||||
|
||||
// NewServer returns a new instance of the Session service
|
||||
func NewServer(sessionMgr *session.SessionManager, settingsMgr *settings.SettingsManager, enf *rbac.Enforcer) *Server {
|
||||
return &Server{sessionMgr, settingsMgr, enf}
|
||||
func NewServer(sessionMgr *session.SessionManager, settingsMgr *settings.SettingsManager, enf *rbac.Enforcer, namespace string) *Server {
|
||||
return &Server{sessionMgr, settingsMgr, enf, namespace}
|
||||
}
|
||||
|
||||
// UpdatePassword updates the password of the currently authenticated account or the account specified in the request.
|
||||
|
|
@ -126,7 +129,22 @@ func (s *Server) CanI(ctx context.Context, r *account.CanIRequest) (*account.Can
|
|||
return nil, status.Errorf(codes.InvalidArgument, "%v does not contain %s", rbac.Resources, r.Resource)
|
||||
}
|
||||
|
||||
ok := s.enf.Enforce(ctx.Value("claims"), r.Resource, r.Action, r.Subresource)
|
||||
subresource := r.Subresource
|
||||
|
||||
// For project-scoped resources, normalize the subresource using security.RBACName
|
||||
// This converts "project/defaultNS/name" to "project/name" for backward compatibility
|
||||
if rbac.ProjectScoped[r.Resource] && s.namespace != "" && subresource != "" {
|
||||
parts := strings.Split(subresource, "/")
|
||||
if len(parts) == 3 {
|
||||
// 3-part format: project/namespace/name
|
||||
// Normalize: if namespace == defaultNS, becomes project/name; otherwise stays project/namespace/name
|
||||
subresource = security.RBACName(s.namespace, parts[0], parts[1], parts[2])
|
||||
}
|
||||
// if 2 parts, always assume the default namespace
|
||||
// else: keep as-is (wildcards, etc.)
|
||||
}
|
||||
|
||||
ok := s.enf.Enforce(ctx.Value("claims"), r.Resource, r.Action, subresource)
|
||||
if ok {
|
||||
return &account.CanIResponse{Value: "yes"}, nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -70,7 +70,7 @@ func newTestAccountServerExt(t *testing.T, ctx context.Context, enforceFn rbac.C
|
|||
enforcer := rbac.NewEnforcer(kubeclientset, testNamespace, common.ArgoCDRBACConfigMapName, nil)
|
||||
enforcer.SetClaimsEnforcerFunc(enforceFn)
|
||||
|
||||
return NewServer(sessionMgr, settingsMgr, enforcer), session.NewServer(sessionMgr, settingsMgr, nil, nil, nil)
|
||||
return NewServer(sessionMgr, settingsMgr, enforcer, testNamespace), session.NewServer(sessionMgr, settingsMgr, nil, nil, nil)
|
||||
}
|
||||
|
||||
func getAdminAccount(mgr *settings.SettingsManager) (*settings.Account, error) {
|
||||
|
|
@ -332,3 +332,137 @@ func TestCanI_GetLogsDeny(t *testing.T) {
|
|||
require.NoError(t, err)
|
||||
assert.Equal(t, "no", resp.Value)
|
||||
}
|
||||
|
||||
func TestCanI_RBACPolicyMatchingWithNormalizedSubresource(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
policy string
|
||||
expectedResp string
|
||||
}{
|
||||
{
|
||||
name: "allow policy without namespace",
|
||||
policy: "p, role:log-viewer, logs, get, myproject/*, allow",
|
||||
expectedResp: "yes",
|
||||
},
|
||||
{
|
||||
name: "deny explicit default namespace policy",
|
||||
policy: "p, role:log-viewer, logs, get, myproject/default/*, allow",
|
||||
expectedResp: "no",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
accountServer, _ := newTestAccountServerExt(t, t.Context(), nil)
|
||||
require.NoError(t, accountServer.enf.SetBuiltinPolicy(tt.policy))
|
||||
accountServer.enf.SetDefaultRole("role:log-viewer")
|
||||
|
||||
resp, err := accountServer.CanI(adminContext(t.Context()), &account.CanIRequest{
|
||||
Resource: "logs",
|
||||
Action: "get",
|
||||
Subresource: "myproject/default/myapp",
|
||||
})
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, tt.expectedResp, resp.Value)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestCanI_NormalizeDefaultNamespace(t *testing.T) {
|
||||
// Test: subresource "myproject/default/myapp" with default namespace "default"
|
||||
// Expected: normalized to "myproject/myapp" (matches */* policy)
|
||||
enforcer := func(_ jwt.Claims, rvals ...any) bool {
|
||||
// Verify the subresource was normalized to 2 segments
|
||||
if len(rvals) >= 4 {
|
||||
if obj, ok := rvals[3].(string); ok {
|
||||
return obj == "myproject/myapp"
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
accountServer, _ := newTestAccountServerExt(t, t.Context(), enforcer)
|
||||
ctx := adminContext(t.Context())
|
||||
|
||||
// UI sends 3-segment format with default namespace
|
||||
resp, err := accountServer.CanI(ctx, &account.CanIRequest{
|
||||
Resource: "logs",
|
||||
Action: "get",
|
||||
Subresource: "myproject/default/myapp", // default is default namespace
|
||||
})
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "yes", resp.Value)
|
||||
}
|
||||
|
||||
func TestCanI_PreserveNonDefaultNamespace(t *testing.T) {
|
||||
// Test: subresource "myproject/other-ns/myapp" with default namespace "default"
|
||||
// Expected: preserved as "myproject/other-ns/myapp" (needs */*/* policy)
|
||||
enforcer := func(_ jwt.Claims, rvals ...any) bool {
|
||||
// Verify the subresource was NOT normalized (3 segments)
|
||||
if len(rvals) >= 4 {
|
||||
if obj, ok := rvals[3].(string); ok {
|
||||
return obj == "myproject/other-ns/myapp"
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
accountServer, _ := newTestAccountServerExt(t, t.Context(), enforcer)
|
||||
ctx := adminContext(t.Context())
|
||||
|
||||
resp, err := accountServer.CanI(ctx, &account.CanIRequest{
|
||||
Resource: "logs",
|
||||
Action: "get",
|
||||
Subresource: "myproject/other-ns/myapp", // other-ns != default
|
||||
})
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "yes", resp.Value)
|
||||
}
|
||||
|
||||
func TestCanI_BackwardCompatibleTwoSegment(t *testing.T) {
|
||||
// Test: old UI sends "myproject/myapp" (2 segments)
|
||||
// Expected: stays as "myproject/myapp"
|
||||
enforcer := func(_ jwt.Claims, rvals ...any) bool {
|
||||
if len(rvals) >= 4 {
|
||||
if obj, ok := rvals[3].(string); ok {
|
||||
return obj == "myproject/myapp"
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
accountServer, _ := newTestAccountServerExt(t, t.Context(), enforcer)
|
||||
ctx := adminContext(t.Context())
|
||||
|
||||
resp, err := accountServer.CanI(ctx, &account.CanIRequest{
|
||||
Resource: "logs",
|
||||
Action: "get",
|
||||
Subresource: "myproject/myapp",
|
||||
})
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "yes", resp.Value)
|
||||
}
|
||||
|
||||
func TestCanI_NonProjectScopedResource(t *testing.T) {
|
||||
// Test: non-project-scoped resources should not be normalized
|
||||
enforcer := func(_ jwt.Claims, rvals ...any) bool {
|
||||
if len(rvals) >= 4 {
|
||||
if obj, ok := rvals[3].(string); ok {
|
||||
// Should receive the original format unchanged
|
||||
return obj == "some/value/here"
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
accountServer, _ := newTestAccountServerExt(t, t.Context(), enforcer)
|
||||
ctx := adminContext(t.Context())
|
||||
|
||||
resp, err := accountServer.CanI(ctx, &account.CanIRequest{
|
||||
Resource: "accounts", // not project-scoped
|
||||
Action: "update",
|
||||
Subresource: "some/value/here",
|
||||
})
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "yes", resp.Value)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1626,7 +1626,8 @@ func (s *Server) WatchResourceTree(q *application.ResourcesQuery, ws application
|
|||
}
|
||||
|
||||
func (s *Server) RevisionMetadata(ctx context.Context, q *application.RevisionMetadataQuery) (*v1alpha1.RevisionMetadata, error) {
|
||||
a, proj, err := s.getApplicationEnforceRBACInformer(ctx, rbac.ActionGet, q.GetProject(), q.GetAppNamespace(), q.GetName())
|
||||
// Read via the client instead of the informer cache to avoid "revision history not found" errors due to stale informer cache
|
||||
a, proj, err := s.getApplicationEnforceRBACClient(ctx, rbac.ActionGet, q.GetProject(), q.GetAppNamespace(), q.GetName(), "")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -2452,11 +2453,13 @@ func (s *Server) resolveRevision(ctx context.Context, app *v1alpha1.Application,
|
|||
}
|
||||
}
|
||||
|
||||
// Do not use cache for revision resolution since this is a user triggered operation
|
||||
resolveRevisionResponse, err := repoClient.ResolveRevision(ctx, &apiclient.ResolveRevisionRequest{
|
||||
Repo: repo,
|
||||
App: app,
|
||||
AmbiguousRevision: ambiguousRevision,
|
||||
SourceIndex: int64(sourceIndex),
|
||||
NoRevisionCache: true,
|
||||
})
|
||||
if err != nil {
|
||||
return "", "", fmt.Errorf("error resolving repo revision: %w", err)
|
||||
|
|
|
|||
|
|
@ -463,7 +463,7 @@ func TestHandlerConstructLogoutURL(t *testing.T) {
|
|||
}
|
||||
} else {
|
||||
if tt.wantErr {
|
||||
t.Errorf("expected error but did not get one")
|
||||
t.Error("expected error but did not get one")
|
||||
} else {
|
||||
require.Equal(t, tt.expectedLogoutURL, tt.responseRecorder.Result().Header["Location"][0])
|
||||
}
|
||||
|
|
|
|||
|
|
@ -686,25 +686,29 @@ func (s *Server) ValidateAccess(ctx context.Context, q *repositorypkg.RepoAccess
|
|||
}
|
||||
|
||||
repo := &v1alpha1.Repository{
|
||||
Repo: q.Repo,
|
||||
Type: q.Type,
|
||||
Name: q.Name,
|
||||
Username: q.Username,
|
||||
Password: q.Password,
|
||||
BearerToken: q.BearerToken,
|
||||
SSHPrivateKey: q.SshPrivateKey,
|
||||
Insecure: q.Insecure,
|
||||
TLSClientCertData: q.TlsClientCertData,
|
||||
TLSClientCertKey: q.TlsClientCertKey,
|
||||
EnableOCI: q.EnableOci,
|
||||
GithubAppPrivateKey: q.GithubAppPrivateKey,
|
||||
GithubAppId: q.GithubAppID,
|
||||
GithubAppInstallationId: q.GithubAppInstallationID,
|
||||
GitHubAppEnterpriseBaseURL: q.GithubAppEnterpriseBaseUrl,
|
||||
Proxy: q.Proxy,
|
||||
GCPServiceAccountKey: q.GcpServiceAccountKey,
|
||||
InsecureOCIForceHttp: q.InsecureOciForceHttp,
|
||||
UseAzureWorkloadIdentity: q.UseAzureWorkloadIdentity,
|
||||
Repo: q.Repo,
|
||||
Type: q.Type,
|
||||
Name: q.Name,
|
||||
Username: q.Username,
|
||||
Password: q.Password,
|
||||
BearerToken: q.BearerToken,
|
||||
SSHPrivateKey: q.SshPrivateKey,
|
||||
Insecure: q.Insecure,
|
||||
TLSClientCertData: q.TlsClientCertData,
|
||||
TLSClientCertKey: q.TlsClientCertKey,
|
||||
EnableOCI: q.EnableOci,
|
||||
GithubAppPrivateKey: q.GithubAppPrivateKey,
|
||||
GithubAppId: q.GithubAppID,
|
||||
GithubAppInstallationId: q.GithubAppInstallationID,
|
||||
GitHubAppEnterpriseBaseURL: q.GithubAppEnterpriseBaseUrl,
|
||||
Proxy: q.Proxy,
|
||||
GCPServiceAccountKey: q.GcpServiceAccountKey,
|
||||
InsecureOCIForceHttp: q.InsecureOciForceHttp,
|
||||
UseAzureWorkloadIdentity: q.UseAzureWorkloadIdentity,
|
||||
AzureServicePrincipalClientId: q.AzureServicePrincipalClientId,
|
||||
AzureServicePrincipalClientSecret: q.AzureServicePrincipalClientSecret,
|
||||
AzureServicePrincipalTenantId: q.AzureServicePrincipalTenantId,
|
||||
AzureActiveDirectoryEndpoint: q.AzureActiveDirectoryEndpoint,
|
||||
}
|
||||
|
||||
// If repo does not have credentials, check if there are credentials stored
|
||||
|
|
@ -737,24 +741,28 @@ func (s *Server) ValidateWriteAccess(ctx context.Context, q *repositorypkg.RepoA
|
|||
}
|
||||
|
||||
repo := &v1alpha1.Repository{
|
||||
Repo: q.Repo,
|
||||
Type: q.Type,
|
||||
Name: q.Name,
|
||||
Username: q.Username,
|
||||
Password: q.Password,
|
||||
BearerToken: q.BearerToken,
|
||||
SSHPrivateKey: q.SshPrivateKey,
|
||||
Insecure: q.Insecure,
|
||||
TLSClientCertData: q.TlsClientCertData,
|
||||
TLSClientCertKey: q.TlsClientCertKey,
|
||||
EnableOCI: q.EnableOci,
|
||||
GithubAppPrivateKey: q.GithubAppPrivateKey,
|
||||
GithubAppId: q.GithubAppID,
|
||||
GithubAppInstallationId: q.GithubAppInstallationID,
|
||||
GitHubAppEnterpriseBaseURL: q.GithubAppEnterpriseBaseUrl,
|
||||
Proxy: q.Proxy,
|
||||
GCPServiceAccountKey: q.GcpServiceAccountKey,
|
||||
UseAzureWorkloadIdentity: q.UseAzureWorkloadIdentity,
|
||||
Repo: q.Repo,
|
||||
Type: q.Type,
|
||||
Name: q.Name,
|
||||
Username: q.Username,
|
||||
Password: q.Password,
|
||||
BearerToken: q.BearerToken,
|
||||
SSHPrivateKey: q.SshPrivateKey,
|
||||
Insecure: q.Insecure,
|
||||
TLSClientCertData: q.TlsClientCertData,
|
||||
TLSClientCertKey: q.TlsClientCertKey,
|
||||
EnableOCI: q.EnableOci,
|
||||
GithubAppPrivateKey: q.GithubAppPrivateKey,
|
||||
GithubAppId: q.GithubAppID,
|
||||
GithubAppInstallationId: q.GithubAppInstallationID,
|
||||
GitHubAppEnterpriseBaseURL: q.GithubAppEnterpriseBaseUrl,
|
||||
Proxy: q.Proxy,
|
||||
GCPServiceAccountKey: q.GcpServiceAccountKey,
|
||||
UseAzureWorkloadIdentity: q.UseAzureWorkloadIdentity,
|
||||
AzureServicePrincipalClientId: q.AzureServicePrincipalClientId,
|
||||
AzureServicePrincipalClientSecret: q.AzureServicePrincipalClientSecret,
|
||||
AzureServicePrincipalTenantId: q.AzureServicePrincipalTenantId,
|
||||
AzureActiveDirectoryEndpoint: q.AzureActiveDirectoryEndpoint,
|
||||
}
|
||||
|
||||
err := s.testRepo(ctx, repo)
|
||||
|
|
|
|||
|
|
@ -95,6 +95,14 @@ message RepoAccessQuery {
|
|||
string bearerToken = 21;
|
||||
// Whether https should be disabled for an OCI repo
|
||||
bool insecureOciForceHttp = 22;
|
||||
// Azure Service Principal Client ID
|
||||
string azureServicePrincipalClientId = 23;
|
||||
// Azure Service Principal Client Secret
|
||||
string azureServicePrincipalClientSecret = 24;
|
||||
// Azure Service Principal Tenant ID
|
||||
string azureServicePrincipalTenantId = 25;
|
||||
// Azure Active Directory Endpoint
|
||||
string azureActiveDirectoryEndpoint = 26;
|
||||
}
|
||||
|
||||
message RepoResponse {}
|
||||
|
|
|
|||
|
|
@ -284,6 +284,19 @@ func TestRepositoryServer(t *testing.T) {
|
|||
require.NoError(t, err)
|
||||
})
|
||||
|
||||
t.Run("Test_validateWriteAccess", func(t *testing.T) {
|
||||
repoServerClient := &mocks.RepoServerServiceClient{}
|
||||
repoServerClient.EXPECT().TestRepository(mock.Anything, mock.Anything).Return(&apiclient.TestRepositoryResponse{}, nil)
|
||||
repoServerClientset := mocks.Clientset{RepoServerServiceClient: repoServerClient}
|
||||
|
||||
s := NewServer(&repoServerClientset, argoDB, enforcer, nil, appLister, projInformer, testNamespace, settingsMgr, true)
|
||||
url := "https://test"
|
||||
_, err := s.ValidateWriteAccess(t.Context(), &repository.RepoAccessQuery{
|
||||
Repo: url,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
})
|
||||
|
||||
t.Run("Test_Get", func(t *testing.T) {
|
||||
repoServerClient := &mocks.RepoServerServiceClient{}
|
||||
repoServerClient.EXPECT().TestRepository(mock.Anything, mock.Anything).Return(&apiclient.TestRepositoryResponse{}, nil)
|
||||
|
|
|
|||
|
|
@ -1067,7 +1067,7 @@ func newArgoCDServiceSet(a *ArgoCDServer) *ArgoCDServiceSet {
|
|||
projectService := project.NewServer(a.Namespace, a.KubeClientset, a.AppClientset, a.enf, projectLock, a.sessionMgr, a.policyEnforcer, a.projInformer, a.settingsMgr, a.db, a.EnableK8sEvent)
|
||||
appsInAnyNamespaceEnabled := len(a.ApplicationNamespaces) > 0
|
||||
settingsService := settings.NewServer(a.settingsMgr, a.RepoClientset, a, a.DisableAuth, appsInAnyNamespaceEnabled, a.HydratorEnabled, a.SyncWithReplaceAllowed)
|
||||
accountService := account.NewServer(a.sessionMgr, a.settingsMgr, a.enf)
|
||||
accountService := account.NewServer(a.sessionMgr, a.settingsMgr, a.enf, a.Namespace)
|
||||
|
||||
notificationService := notification.NewServer(a.apiFactory)
|
||||
certificateService := certificate.NewServer(a.db, a.enf)
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ FROM docker.io/library/node:22.9.0@sha256:8398ea18b8b72817c84af283f72daed9629af2
|
|||
|
||||
FROM docker.io/library/golang:1.26.2@sha256:5f3787b7f902c07c7ec4f3aa91a301a3eda8133aa32661a3b3a3a86ab3a68a36 AS golang
|
||||
|
||||
FROM docker.io/library/registry:3.1@sha256:b0f3668eb14daa3089aee66b4afd65bf2c2065439d6b5b6357bd3ba711fcf5bd AS registry
|
||||
FROM docker.io/library/registry:3.1@sha256:8a7c1aae9db5028cbc1cfe83e5969d270a50e8bc0b72eef3cc5657542ec383c9 AS registry
|
||||
|
||||
FROM docker.io/bitnamilegacy/kubectl:1.32@sha256:9524faf8e3cefb47fa28244a5d15f95ec21a73d963273798e593e61f80712333 AS kubectl
|
||||
|
||||
|
|
|
|||
|
|
@ -183,7 +183,7 @@ func TestManagedByURLFallbackToCurrentInstance(t *testing.T) {
|
|||
}
|
||||
}
|
||||
if !found {
|
||||
t.Logf("Returned links:")
|
||||
t.Log("Returned links:")
|
||||
for _, link := range links.Items {
|
||||
if link.Url != nil {
|
||||
t.Logf("- %s", *link.Url)
|
||||
|
|
|
|||
|
|
@ -1,18 +1,17 @@
|
|||
import * as React from 'react';
|
||||
|
||||
export class NodeUpdateAnimation extends React.PureComponent<{resourceVersion: string}, {ready: boolean}> {
|
||||
constructor(props: {resourceVersion: string}) {
|
||||
super(props);
|
||||
this.state = {ready: false};
|
||||
}
|
||||
/**
|
||||
* When the resource version changes, we want to trigger an animation to indicate that the resource has been updated. This component will be rendered as a child of the node and will update itself when the resource version changes leading to a re-render, which triggers the animation.
|
||||
* @param props Resource version
|
||||
* @returns
|
||||
*/
|
||||
export const NodeUpdateAnimation = (props: {resourceVersion: string}) => {
|
||||
const [animate, setAnimation] = React.useState(false);
|
||||
React.useEffect(() => {
|
||||
return () => {
|
||||
setAnimation(true);
|
||||
};
|
||||
}, [props.resourceVersion]);
|
||||
|
||||
public render() {
|
||||
return this.state.ready && <div key={this.props.resourceVersion} className='application-resource-tree__node-animation' />;
|
||||
}
|
||||
|
||||
public componentDidUpdate(prevProps: {resourceVersion: string}) {
|
||||
if (prevProps.resourceVersion && this.props.resourceVersion !== prevProps.resourceVersion) {
|
||||
this.setState({ready: true});
|
||||
}
|
||||
}
|
||||
}
|
||||
return animate && <div key={props.resourceVersion} className='application-resource-tree__node-animation' />;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -280,8 +280,8 @@ export const ResourceDetails = (props: ResourceDetailsProps) => {
|
|||
|
||||
const settings = await services.authService.settings();
|
||||
const execEnabled = settings.execEnabled;
|
||||
const logsAllowed = await services.accounts.canI('logs', 'get', application.spec.project + '/' + application.metadata.name);
|
||||
const execAllowed = execEnabled && (await services.accounts.canI('exec', 'create', application.spec.project + '/' + application.metadata.name));
|
||||
const logsAllowed = await services.accounts.canI('logs', 'get', AppUtils.appRBACName(application));
|
||||
const execAllowed = execEnabled && (await services.accounts.canI('exec', 'create', AppUtils.appRBACName(application)));
|
||||
const links = await services.applications.getResourceLinks(application.metadata.name, application.metadata.namespace, selectedNode).catch(() => null);
|
||||
const resourceActionsMenuItems = await AppUtils.getResourceActionsMenuItems(selectedNode, application.metadata, appContext);
|
||||
return {controlledState, liveState, events, podState, execEnabled, execAllowed, logsAllowed, links, childResources, resourceActionsMenuItems};
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ import {
|
|||
} from '../../shared/models';
|
||||
import * as jsYaml from 'js-yaml';
|
||||
import {
|
||||
appRBACName,
|
||||
ComparisonStatusIcon,
|
||||
getAppOperationState,
|
||||
getOperationType,
|
||||
|
|
@ -892,4 +893,54 @@ status:
|
|||
|
||||
expect(reason).toBe('SchedulingGated');
|
||||
});
|
||||
});
|
||||
|
||||
describe('appRBACName', () => {
|
||||
it('returns project/namespace/name when namespace is defined', () => {
|
||||
const app = {
|
||||
metadata: {
|
||||
name: 'my-app',
|
||||
namespace: 'my-namespace'
|
||||
},
|
||||
spec: {
|
||||
project: 'my-project'
|
||||
}
|
||||
} as Application;
|
||||
|
||||
const result = appRBACName(app);
|
||||
|
||||
expect(result).toBe('my-project/my-namespace/my-app');
|
||||
});
|
||||
|
||||
it('returns project/name when namespace is undefined', () => {
|
||||
const app = {
|
||||
metadata: {
|
||||
name: 'my-app'
|
||||
},
|
||||
spec: {
|
||||
project: 'my-project'
|
||||
}
|
||||
} as Application;
|
||||
|
||||
const result = appRBACName(app);
|
||||
|
||||
expect(result).toBe('my-project/my-app');
|
||||
});
|
||||
|
||||
it('handles empty namespace string as undefined', () => {
|
||||
const app = {
|
||||
metadata: {
|
||||
name: 'test-app',
|
||||
namespace: ''
|
||||
},
|
||||
spec: {
|
||||
project: 'test-project'
|
||||
}
|
||||
} as Application;
|
||||
|
||||
// Note: The function uses a falsy check on namespace, so empty string is treated the same as undefined
|
||||
const result = appRBACName(app);
|
||||
|
||||
expect(result).toBe('test-project/test-app');
|
||||
});
|
||||
});
|
||||
|
|
@ -749,7 +749,7 @@ function getActionItems(
|
|||
|
||||
const logsAction = isApp(application)
|
||||
? services.accounts
|
||||
.canI('logs', 'get', application.spec.project + '/' + application.metadata.name)
|
||||
.canI('logs', 'get', appRBACName(application))
|
||||
.then(async allowed => {
|
||||
if (allowed && (isPod || findChildPod(resource, tree as appModels.ApplicationTree))) {
|
||||
return [
|
||||
|
|
@ -776,7 +776,7 @@ function getActionItems(
|
|||
? services.authService
|
||||
.settings()
|
||||
.then(async settings => {
|
||||
const execAllowed = settings.execEnabled && (await services.accounts.canI('exec', 'create', application.spec.project + '/' + application.metadata.name));
|
||||
const execAllowed = settings.execEnabled && (await services.accounts.canI('exec', 'create', appRBACName(application)));
|
||||
if (isPod && execAllowed) {
|
||||
return [
|
||||
{
|
||||
|
|
@ -1829,6 +1829,22 @@ export function appQualifiedName(app: appModels.AbstractApplication, nsEnabled:
|
|||
return (nsEnabled ? app.metadata.namespace + '/' : '') + app.metadata.name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs the RBAC subresource name for canI() checks.
|
||||
**/
|
||||
export function appRBACName(app: appModels.Application): string {
|
||||
const project = app.spec.project;
|
||||
const namespace = app.metadata.namespace;
|
||||
const name = app.metadata.name;
|
||||
|
||||
// Always include namespace if available - server will normalize
|
||||
if (namespace) {
|
||||
return `${project}/${namespace}/${name}`;
|
||||
}
|
||||
// Fallback to 2-segment format if namespace is missing
|
||||
return `${project}/${name}`;
|
||||
}
|
||||
|
||||
export function appInstanceName(app: appModels.AbstractApplication): string {
|
||||
return app.metadata.namespace + '_' + app.metadata.name;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -82,6 +82,21 @@ interface NewGoogleCloudSourceRepoParams {
|
|||
write: boolean;
|
||||
}
|
||||
|
||||
interface NewAzureServicePrincipalRepoParams {
|
||||
type: string;
|
||||
name: string;
|
||||
url: string;
|
||||
azureServicePrincipalClientId: string;
|
||||
azureServicePrincipalClientSecret: string;
|
||||
azureServicePrincipalTenantId: string;
|
||||
azureActiveDirectoryEndpoint: string;
|
||||
proxy: string;
|
||||
noProxy: string;
|
||||
project?: string;
|
||||
// write should be true if saving as a write credential.
|
||||
write: boolean;
|
||||
}
|
||||
|
||||
interface NewSSHRepoCredsParams {
|
||||
url: string;
|
||||
sshPrivateKey: string;
|
||||
|
|
@ -128,11 +143,25 @@ interface NewGoogleCloudSourceRepoCredsParams {
|
|||
write: boolean;
|
||||
}
|
||||
|
||||
interface NewAzureServicePrincipalRepoCredsParams {
|
||||
url: string;
|
||||
azureServicePrincipalClientId: string;
|
||||
azureServicePrincipalClientSecret: string;
|
||||
azureServicePrincipalTenantId: string;
|
||||
azureActiveDirectoryEndpoint: string;
|
||||
proxy: string;
|
||||
noProxy: string;
|
||||
project?: string;
|
||||
// write should be true if saving as a write credential.
|
||||
write: boolean;
|
||||
}
|
||||
|
||||
export enum ConnectionMethod {
|
||||
SSH = 'via SSH',
|
||||
HTTPS = 'via HTTP/HTTPS',
|
||||
GITHUBAPP = 'via GitHub App',
|
||||
GOOGLECLOUD = 'via Google Cloud'
|
||||
GOOGLECLOUD = 'via Google Cloud',
|
||||
AZURESERVICEPRINCIPAL = 'via Azure Service Principal'
|
||||
}
|
||||
|
||||
export const ReposList = ({match, location}: RouteComponentProps) => {
|
||||
|
|
@ -172,8 +201,15 @@ export const ReposList = ({match, location}: RouteComponentProps) => {
|
|||
{method.toUpperCase()} <i className='fa fa-caret-down' />
|
||||
</p>
|
||||
)}
|
||||
items={[ConnectionMethod.SSH, ConnectionMethod.HTTPS, ConnectionMethod.GITHUBAPP, ConnectionMethod.GOOGLECLOUD].map(
|
||||
(connectMethod: ConnectionMethod.SSH | ConnectionMethod.HTTPS | ConnectionMethod.GITHUBAPP | ConnectionMethod.GOOGLECLOUD) => ({
|
||||
items={[ConnectionMethod.SSH, ConnectionMethod.HTTPS, ConnectionMethod.GITHUBAPP, ConnectionMethod.GOOGLECLOUD, ConnectionMethod.AZURESERVICEPRINCIPAL].map(
|
||||
(
|
||||
connectMethod:
|
||||
| ConnectionMethod.SSH
|
||||
| ConnectionMethod.HTTPS
|
||||
| ConnectionMethod.GITHUBAPP
|
||||
| ConnectionMethod.GOOGLECLOUD
|
||||
| ConnectionMethod.AZURESERVICEPRINCIPAL
|
||||
) => ({
|
||||
title: connectMethod.toUpperCase(),
|
||||
action: () => {
|
||||
onSelection(connectMethod);
|
||||
|
|
@ -191,7 +227,7 @@ export const ReposList = ({match, location}: RouteComponentProps) => {
|
|||
};
|
||||
|
||||
const onChooseDefaultValues = (): FormValues => {
|
||||
return {type: 'git', ghType: 'GitHub', write: false};
|
||||
return {type: 'git', ghType: 'GitHub', azureType: 'Azure Public Cloud', write: false};
|
||||
};
|
||||
|
||||
const onValidateErrors = (params: FormValues): FormErrors => {
|
||||
|
|
@ -233,6 +269,16 @@ export const ReposList = ({match, location}: RouteComponentProps) => {
|
|||
gcpServiceAccountKey: !googleCloudValues.gcpServiceAccountKey && 'GCP service account key is required',
|
||||
depth: googleCloudValues.depth != undefined && googleCloudValues.depth < 0 && 'Depth must be a non-negative number'
|
||||
};
|
||||
case ConnectionMethod.AZURESERVICEPRINCIPAL:
|
||||
const azureServicePrincipalValues = params as NewAzureServicePrincipalRepoParams;
|
||||
return {
|
||||
url:
|
||||
(!azureServicePrincipalValues.url && 'Repository URL is required') ||
|
||||
(credsTemplate && !isHTTPOrHTTPSUrl(azureServicePrincipalValues.url) && 'Not a valid HTTP/HTTPS URL'),
|
||||
azureServicePrincipalClientId: !azureServicePrincipalValues.azureServicePrincipalClientId && 'Azure Service Principal Client ID is required',
|
||||
azureServicePrincipalClientSecret: !azureServicePrincipalValues.azureServicePrincipalClientSecret && 'Azure Service Principal Client Secret is required',
|
||||
azureServicePrincipalTenantId: !azureServicePrincipalValues.azureServicePrincipalTenantId && 'Azure Service Principal Tenant ID is required'
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -283,6 +329,8 @@ export const ReposList = ({match, location}: RouteComponentProps) => {
|
|||
return connectGitHubAppRepo(params as NewGitHubAppRepoParams);
|
||||
case ConnectionMethod.GOOGLECLOUD:
|
||||
return connectGoogleCloudSourceRepo(params as NewGoogleCloudSourceRepoParams);
|
||||
case ConnectionMethod.AZURESERVICEPRINCIPAL:
|
||||
return connectAzureServicePrincipalRepo(params as NewAzureServicePrincipalRepoParams);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -313,9 +361,9 @@ export const ReposList = ({match, location}: RouteComponentProps) => {
|
|||
return url.replace('https://', '').replace('oci://', '');
|
||||
};
|
||||
|
||||
// only connections of git type which is not via GitHub App are updatable
|
||||
// only connections of git type which are not via GitHub App or Azure Service Principal are updatable
|
||||
const isRepoUpdatable = (repo: models.Repository) => {
|
||||
return isHTTPOrHTTPSUrl(repo.repo) && repo.type === 'git' && !repo.githubAppID;
|
||||
return isHTTPOrHTTPSUrl(repo.repo) && repo.type === 'git' && !repo.githubAppID && !repo.azureServicePrincipalClientId;
|
||||
};
|
||||
|
||||
// Forces a reload of configured repositories, circumventing the cache
|
||||
|
|
@ -466,7 +514,7 @@ export const ReposList = ({match, location}: RouteComponentProps) => {
|
|||
}
|
||||
};
|
||||
|
||||
// Connect a new repository or create a repository credentials for GitHub App repositories
|
||||
// Connect a new repository or create a repository credentials for Google Cloud Source repositories
|
||||
const connectGoogleCloudSourceRepo = async (params: NewGoogleCloudSourceRepoParams) => {
|
||||
if (credsTemplate.current) {
|
||||
createGoogleCloudSourceCreds({
|
||||
|
|
@ -495,6 +543,40 @@ export const ReposList = ({match, location}: RouteComponentProps) => {
|
|||
}
|
||||
};
|
||||
|
||||
// Connect a new repository or create a repository credentials for Azure Service Principal repositories
|
||||
const connectAzureServicePrincipalRepo = async (params: NewAzureServicePrincipalRepoParams) => {
|
||||
if (credsTemplate.current) {
|
||||
createAzureServicePrincipalCreds({
|
||||
url: params.url,
|
||||
azureServicePrincipalClientId: params.azureServicePrincipalClientId,
|
||||
azureServicePrincipalClientSecret: params.azureServicePrincipalClientSecret,
|
||||
azureServicePrincipalTenantId: params.azureServicePrincipalTenantId,
|
||||
azureActiveDirectoryEndpoint: params.azureActiveDirectoryEndpoint,
|
||||
proxy: params.proxy,
|
||||
noProxy: params.noProxy,
|
||||
write: params.write
|
||||
});
|
||||
} else {
|
||||
setConnecting(true);
|
||||
try {
|
||||
if (params.write) {
|
||||
await services.repos.createAzureServicePrincipalWrite(params);
|
||||
} else {
|
||||
await services.repos.createAzureServicePrincipal(params);
|
||||
}
|
||||
repoLoader.current.reload();
|
||||
setConnectRepo(false);
|
||||
} catch (e) {
|
||||
ctx.notifications.show({
|
||||
content: <ErrorNotification title='Unable to connect Azure Service Principal repository' e={e} />,
|
||||
type: NotificationType.Error
|
||||
});
|
||||
} finally {
|
||||
setConnecting(false);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const createHTTPSCreds = async (params: NewHTTPSRepoCredsParams) => {
|
||||
try {
|
||||
if (params.write) {
|
||||
|
|
@ -563,6 +645,23 @@ export const ReposList = ({match, location}: RouteComponentProps) => {
|
|||
}
|
||||
};
|
||||
|
||||
const createAzureServicePrincipalCreds = async (params: NewAzureServicePrincipalRepoCredsParams) => {
|
||||
try {
|
||||
if (params.write) {
|
||||
await services.repocreds.createAzureServicePrincipalWrite(params);
|
||||
} else {
|
||||
await services.repocreds.createAzureServicePrincipal(params);
|
||||
}
|
||||
credsLoader.current.reload();
|
||||
setConnectRepo(false);
|
||||
} catch (e) {
|
||||
ctx.notifications.show({
|
||||
content: <ErrorNotification title='Unable to create Azure Service Principal credentials' e={e} />,
|
||||
type: NotificationType.Error
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// Remove a repository from the configuration
|
||||
const disconnectRepo = async (repo: string, project: string, write: boolean) => {
|
||||
const confirmed = await ctx.popup.confirm('Disconnect repository', `Are you sure you want to disconnect '${repo}'?`);
|
||||
|
|
@ -1322,6 +1421,59 @@ export const ReposList = ({match, location}: RouteComponentProps) => {
|
|||
</div>
|
||||
</div>
|
||||
)}
|
||||
{method === ConnectionMethod.AZURESERVICEPRINCIPAL && (
|
||||
<div className='white-box'>
|
||||
<p>CONNECT REPO USING AZURE SERVICE PRINCIPAL</p>
|
||||
<div className='argo-form-row'>
|
||||
<FormField
|
||||
formApi={formApi}
|
||||
label='Type'
|
||||
field='azureType'
|
||||
component={FormSelect}
|
||||
componentProps={{options: ['Azure Public Cloud', 'Azure Other Cloud']}}
|
||||
/>
|
||||
</div>
|
||||
{formApi.getFormState().values.azureType === 'Azure Other Cloud' && (
|
||||
<div className='argo-form-row'>
|
||||
<FormField
|
||||
formApi={formApi}
|
||||
label='Azure Active Directory Endpoint (e.g. https://login.microsoftonline.de)'
|
||||
field='azureActiveDirectoryEndpoint'
|
||||
component={Text}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
<div className='argo-form-row'>
|
||||
<FormField formApi={formApi} label='Project' field='project' component={AutocompleteField} componentProps={{items: projects}} />
|
||||
</div>
|
||||
<div className='argo-form-row'>
|
||||
<FormField formApi={formApi} label='Repository URL' field='url' component={Text} />
|
||||
</div>
|
||||
<div className='argo-form-row'>
|
||||
<FormField formApi={formApi} label='AzureTenant ID' field='azureServicePrincipalTenantId' component={Text} />
|
||||
</div>
|
||||
<div className='argo-form-row'>
|
||||
<FormField formApi={formApi} label='Azure Client ID' field='azureServicePrincipalClientId' component={Text} />
|
||||
</div>
|
||||
<div className='argo-form-row'>
|
||||
<FormField formApi={formApi} label='Azure Client Secret' field='azureServicePrincipalClientSecret' component={Text} />
|
||||
</div>
|
||||
<div className='argo-form-row'>
|
||||
<FormField formApi={formApi} label='Skip server verification' field='insecure' component={CheckboxField} />
|
||||
<HelpIcon title='This setting is ignored when creating as credential template.' />
|
||||
</div>
|
||||
<div className='argo-form-row'>
|
||||
<FormField formApi={formApi} label='Enable LFS support (Git only)' field='enableLfs' component={CheckboxField} />
|
||||
<HelpIcon title='This setting is ignored when creating as credential template.' />
|
||||
</div>
|
||||
<div className='argo-form-row'>
|
||||
<FormField formApi={formApi} label='Proxy (optional)' field='proxy' component={Text} />
|
||||
</div>
|
||||
<div className='argo-form-row'>
|
||||
<FormField formApi={formApi} label='NoProxy (optional)' field='noProxy' component={Text} />
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</form>
|
||||
)}
|
||||
</Form>
|
||||
|
|
|
|||
|
|
@ -677,6 +677,10 @@ export interface Repository {
|
|||
enableOCI: boolean;
|
||||
useAzureWorkloadIdentity: boolean;
|
||||
depth?: number;
|
||||
azureServicePrincipalClientId?: string;
|
||||
azureServicePrincipalClientSecret?: string;
|
||||
azureServicePrincipalTenantId?: string;
|
||||
azureActiveDirectoryEndpoint?: string;
|
||||
}
|
||||
|
||||
export interface RepositoryList extends ItemsList<Repository> {}
|
||||
|
|
|
|||
|
|
@ -64,6 +64,19 @@ export interface GoogleCloudSourceQuery {
|
|||
depth?: number;
|
||||
}
|
||||
|
||||
export interface AzureServicePrincipalQuery {
|
||||
type: string;
|
||||
name: string;
|
||||
url: string;
|
||||
azureActiveDirectoryEndpoint: string;
|
||||
azureServicePrincipalClientId: string;
|
||||
azureServicePrincipalClientSecret: string;
|
||||
azureServicePrincipalTenantId: string;
|
||||
proxy: string;
|
||||
noProxy: string;
|
||||
project?: string;
|
||||
}
|
||||
|
||||
export class RepositoriesService {
|
||||
public list(): Promise<models.Repository[]> {
|
||||
return requests
|
||||
|
|
@ -311,6 +324,42 @@ export class RepositoriesService {
|
|||
.then(res => res.body as models.Repository);
|
||||
}
|
||||
|
||||
public createAzureServicePrincipal(q: AzureServicePrincipalQuery): Promise<models.Repository> {
|
||||
return requests
|
||||
.post('/repositories')
|
||||
.send({
|
||||
type: q.type,
|
||||
name: q.name,
|
||||
repo: q.url,
|
||||
azureServicePrincipalClientId: q.azureServicePrincipalClientId,
|
||||
azureServicePrincipalClientSecret: q.azureServicePrincipalClientSecret,
|
||||
azureServicePrincipalTenantId: q.azureServicePrincipalTenantId,
|
||||
azureActiveDirectoryEndpoint: q.azureActiveDirectoryEndpoint,
|
||||
proxy: q.proxy,
|
||||
noProxy: q.noProxy,
|
||||
project: q.project
|
||||
})
|
||||
.then(res => res.body as models.Repository);
|
||||
}
|
||||
|
||||
public createAzureServicePrincipalWrite(q: AzureServicePrincipalQuery): Promise<models.Repository> {
|
||||
return requests
|
||||
.post('/write-repositories')
|
||||
.send({
|
||||
type: q.type,
|
||||
name: q.name,
|
||||
repo: q.url,
|
||||
azureServicePrincipalClientId: q.azureServicePrincipalClientId,
|
||||
azureServicePrincipalClientSecret: q.azureServicePrincipalClientSecret,
|
||||
azureServicePrincipalTenantId: q.azureServicePrincipalTenantId,
|
||||
azureActiveDirectoryEndpoint: q.azureActiveDirectoryEndpoint,
|
||||
proxy: q.proxy,
|
||||
noProxy: q.noProxy,
|
||||
project: q.project
|
||||
})
|
||||
.then(res => res.body as models.Repository);
|
||||
}
|
||||
|
||||
public delete(url: string, project: string): Promise<models.Repository> {
|
||||
return requests
|
||||
.delete(`/repositories/${encodeURIComponent(url)}?appProject=${project}`)
|
||||
|
|
|
|||
|
|
@ -37,6 +37,16 @@ export interface GoogleCloudSourceCreds {
|
|||
gcpServiceAccountKey: string;
|
||||
}
|
||||
|
||||
export interface AzureServicePrincipalCreds {
|
||||
url: string;
|
||||
azureActiveDirectoryEndpoint: string;
|
||||
azureServicePrincipalClientId: string;
|
||||
azureServicePrincipalClientSecret: string;
|
||||
azureServicePrincipalTenantId: string;
|
||||
proxy: string;
|
||||
noProxy: string;
|
||||
}
|
||||
|
||||
export class RepoCredsService {
|
||||
public list(): Promise<models.RepoCreds[]> {
|
||||
return requests
|
||||
|
|
@ -108,6 +118,20 @@ export class RepoCredsService {
|
|||
.then(res => res.body as models.RepoCreds);
|
||||
}
|
||||
|
||||
public createAzureServicePrincipal(creds: AzureServicePrincipalCreds): Promise<models.RepoCreds> {
|
||||
return requests
|
||||
.post('/repocreds')
|
||||
.send(creds)
|
||||
.then(res => res.body as models.RepoCreds);
|
||||
}
|
||||
|
||||
public createAzureServicePrincipalWrite(creds: AzureServicePrincipalCreds): Promise<models.RepoCreds> {
|
||||
return requests
|
||||
.post('/write-repocreds')
|
||||
.send(creds)
|
||||
.then(res => res.body as models.RepoCreds);
|
||||
}
|
||||
|
||||
public delete(url: string): Promise<models.RepoCreds> {
|
||||
return requests
|
||||
.delete(`/repocreds/${encodeURIComponent(url)}`)
|
||||
|
|
|
|||
|
|
@ -478,10 +478,16 @@ func validateRepo(ctx context.Context,
|
|||
}
|
||||
}
|
||||
|
||||
kubeServerVersion := cluster.Info.ServerVersion
|
||||
apiVersions := APIResourcesToStrings(apiGroups, true)
|
||||
|
||||
// If using the source hydrator, check the dry source instead of the sync source, since the sync source branch may
|
||||
// not exist yet.
|
||||
if app.Spec.SourceHydrator != nil {
|
||||
sources = []argoappv1.ApplicationSource{app.Spec.SourceHydrator.GetDrySource()}
|
||||
// For the dry source, we dont want to sendRuntimeState during the generation
|
||||
kubeServerVersion = ""
|
||||
apiVersions = nil
|
||||
}
|
||||
|
||||
refSources, err := GetRefSources(ctx, sources, app.Spec.Project, db.GetRepository, []string{})
|
||||
|
|
@ -498,8 +504,8 @@ func validateRepo(ctx context.Context,
|
|||
proj,
|
||||
sources,
|
||||
repoClient,
|
||||
cluster.Info.ServerVersion,
|
||||
APIResourcesToStrings(apiGroups, true),
|
||||
kubeServerVersion,
|
||||
apiVersions,
|
||||
permittedHelmCredentials,
|
||||
permittedOCICredentials,
|
||||
enabledSourceTypes,
|
||||
|
|
|
|||
|
|
@ -456,6 +456,95 @@ func TestValidateRepo(t *testing.T) {
|
|||
assert.Equal(t, kustomizeOptions, receivedRequest.KustomizeOptions)
|
||||
}
|
||||
|
||||
func TestValidateRepo_SourceHydrator(t *testing.T) {
|
||||
repoPath, err := filepath.Abs("./../..")
|
||||
require.NoError(t, err)
|
||||
|
||||
apiResources := []kube.APIResourceInfo{{
|
||||
GroupVersionResource: schema.GroupVersionResource{Group: "apps", Version: "v1beta1"},
|
||||
GroupKind: schema.GroupKind{Kind: "Deployment"},
|
||||
}, {
|
||||
GroupVersionResource: schema.GroupVersionResource{Group: "apps", Version: "v1beta2"},
|
||||
GroupKind: schema.GroupKind{Kind: "Deployment"},
|
||||
}}
|
||||
kubeVersion := "v1.16"
|
||||
|
||||
repoURL := "file://" + repoPath
|
||||
repo := &argoappv1.Repository{Repo: repoURL, Type: "git"}
|
||||
cluster := &argoappv1.Cluster{Server: "sample server"}
|
||||
|
||||
app := &argoappv1.Application{
|
||||
Spec: argoappv1.ApplicationSpec{
|
||||
Destination: argoappv1.ApplicationDestination{
|
||||
Server: cluster.Server,
|
||||
Namespace: "default",
|
||||
},
|
||||
SourceHydrator: &argoappv1.SourceHydrator{
|
||||
DrySource: argoappv1.DrySource{
|
||||
RepoURL: repoURL,
|
||||
TargetRevision: "HEAD",
|
||||
Path: "guestbook",
|
||||
},
|
||||
SyncSource: argoappv1.SyncSource{
|
||||
TargetBranch: "env/test",
|
||||
Path: "guestbook",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
proj := &argoappv1.AppProject{
|
||||
Spec: argoappv1.AppProjectSpec{
|
||||
SourceRepos: []string{"*"},
|
||||
},
|
||||
}
|
||||
|
||||
repoClient := &mocks.RepoServerServiceClient{}
|
||||
|
||||
syncSource := app.Spec.GetSource()
|
||||
repoClient.EXPECT().TestRepository(mock.Anything, mock.MatchedBy(func(req *apiclient.TestRepositoryRequest) bool {
|
||||
return req.Repo.Repo == syncSource.RepoURL
|
||||
})).Return(&apiclient.TestRepositoryResponse{VerifiedRepository: true}, nil)
|
||||
|
||||
var receivedRequest *apiclient.ManifestRequest
|
||||
repoClient.EXPECT().GenerateManifest(mock.Anything, mock.MatchedBy(func(req *apiclient.ManifestRequest) bool {
|
||||
receivedRequest = req
|
||||
return true
|
||||
})).Return(nil, nil)
|
||||
|
||||
repoClientSet := &mocks.Clientset{RepoServerServiceClient: repoClient}
|
||||
|
||||
db := &dbmocks.ArgoDB{}
|
||||
db.EXPECT().GetRepository(mock.Anything, repoURL, "").Return(repo, nil).Maybe()
|
||||
db.EXPECT().ListHelmRepositories(mock.Anything).Return(nil, nil)
|
||||
db.EXPECT().ListOCIRepositories(mock.Anything).Return(nil, nil)
|
||||
db.EXPECT().GetCluster(mock.Anything, cluster.Server).Return(cluster, nil)
|
||||
db.EXPECT().GetAllHelmRepositoryCredentials(mock.Anything).Return(nil, nil)
|
||||
db.EXPECT().GetAllOCIRepositoryCredentials(mock.Anything).Return(nil, nil)
|
||||
|
||||
cm := corev1.ConfigMap{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "argocd-cm",
|
||||
Namespace: test.FakeArgoCDNamespace,
|
||||
Labels: map[string]string{"app.kubernetes.io/part-of": "argocd"},
|
||||
},
|
||||
}
|
||||
kubeClient := fake.NewClientset(&cm)
|
||||
settingsMgr := settings.NewSettingsManager(t.Context(), kubeClient, test.FakeArgoCDNamespace)
|
||||
|
||||
conditions, err := ValidateRepo(t.Context(), app, repoClientSet, db, &kubetest.MockKubectlCmd{Version: kubeVersion, APIResources: apiResources}, proj, settingsMgr)
|
||||
|
||||
require.NoError(t, err)
|
||||
assert.Empty(t, conditions)
|
||||
require.NotNil(t, receivedRequest)
|
||||
|
||||
drySource := app.Spec.SourceHydrator.GetDrySource()
|
||||
assert.Equal(t, &drySource, receivedRequest.ApplicationSource)
|
||||
assert.Equal(t, "HEAD", receivedRequest.Revision)
|
||||
assert.Empty(t, receivedRequest.KubeVersion, "KubeVersion must be empty for dry sources to match hydrator cache keys")
|
||||
assert.Nil(t, receivedRequest.ApiVersions, "ApiVersions must be nil for dry sources to match hydrator cache keys")
|
||||
}
|
||||
|
||||
func TestFormatAppConditions(t *testing.T) {
|
||||
conditions := []argoappv1.ApplicationCondition{
|
||||
{
|
||||
|
|
|
|||
|
|
@ -80,7 +80,7 @@ func TestSetLogFormat(t *testing.T) {
|
|||
if errors.As(err, &e) {
|
||||
return
|
||||
}
|
||||
t.Fatalf("expected fatal exit for invalid log format")
|
||||
t.Fatal("expected fatal exit for invalid log format")
|
||||
} else {
|
||||
SetLogFormat(tt.logFormat)
|
||||
assert.Equal(t, tt.expected, os.Getenv(common.EnvLogFormat))
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ import (
|
|||
certutil "github.com/argoproj/argo-cd/v3/util/cert"
|
||||
)
|
||||
|
||||
// A struct representing an entry in the list of SSH known hosts.
|
||||
// SSHKnownHostsEntry represents an entry in the list of SSH known hosts.
|
||||
type SSHKnownHostsEntry struct {
|
||||
// Hostname the key is for
|
||||
Host string
|
||||
|
|
@ -28,7 +28,7 @@ type SSHKnownHostsEntry struct {
|
|||
Fingerprint string
|
||||
}
|
||||
|
||||
// A representation of a TLS certificate
|
||||
// TLSCertificate represents a TLS certificate.
|
||||
type TLSCertificate struct {
|
||||
// Subject of the certificate
|
||||
Subject string
|
||||
|
|
@ -38,7 +38,7 @@ type TLSCertificate struct {
|
|||
Data string
|
||||
}
|
||||
|
||||
// Helper struct for certificate selection
|
||||
// CertificateListSelector is a helper struct for certificate selection.
|
||||
type CertificateListSelector struct {
|
||||
// Pattern to match the hostname with
|
||||
HostNamePattern string
|
||||
|
|
@ -48,7 +48,7 @@ type CertificateListSelector struct {
|
|||
CertSubType string
|
||||
}
|
||||
|
||||
// Get a list of all configured repository certificates matching the given
|
||||
// ListRepoCertificates returns a list of all configured repository certificates matching the given
|
||||
// selector. The list of certificates explicitly excludes the CertData of
|
||||
// the certificates, and only returns the metadata including CertInfo field.
|
||||
//
|
||||
|
|
@ -57,7 +57,7 @@ type CertificateListSelector struct {
|
|||
// the string "SHA256:"
|
||||
// - For TLS certs, the Subject of the X509 cert as a string in DN notation
|
||||
func (db *db) ListRepoCertificates(_ context.Context, selector *CertificateListSelector) (*appsv1.RepositoryCertificateList, error) {
|
||||
// selector may be given as nil, but we need at least an empty data structure
|
||||
// selector may be given as nil, but we need at least an empty data structure,
|
||||
// so we create it if necessary.
|
||||
if selector == nil {
|
||||
selector = &CertificateListSelector{}
|
||||
|
|
@ -122,7 +122,7 @@ func (db *db) ListRepoCertificates(_ context.Context, selector *CertificateListS
|
|||
}, nil
|
||||
}
|
||||
|
||||
// Get a single certificate from the datastore
|
||||
// GetRepoCertificate returns a single certificate from the datastore
|
||||
func (db *db) GetRepoCertificate(_ context.Context, serverType string, serverName string) (*appsv1.RepositoryCertificate, error) {
|
||||
if serverType == "ssh" {
|
||||
sshKnownHostsList, err := db.getSSHKnownHostsData()
|
||||
|
|
@ -147,7 +147,7 @@ func (db *db) GetRepoCertificate(_ context.Context, serverType string, serverNam
|
|||
return nil, nil
|
||||
}
|
||||
|
||||
// Create one or more repository certificates and returns a list of certificates
|
||||
// CreateRepoCertificate creates one or more repository certificates and returns a list of certificates
|
||||
// actually created.
|
||||
func (db *db) CreateRepoCertificate(ctx context.Context, certificates *appsv1.RepositoryCertificateList, upsert bool) (*appsv1.RepositoryCertificateList, error) {
|
||||
var (
|
||||
|
|
@ -178,7 +178,7 @@ func (db *db) CreateRepoCertificate(ctx context.Context, certificates *appsv1.Re
|
|||
return nil, fmt.Errorf("invalid hostname in request: %s", certificate.ServerName)
|
||||
} else if certificate.CertType == "ssh" {
|
||||
// Matches "[hostname]:port" format
|
||||
reExtract := regexp.MustCompile(`^\[(.*)\]:\d+$`)
|
||||
reExtract := regexp.MustCompile(`^\[(.*)]:\d+$`)
|
||||
matches := reExtract.FindStringSubmatch(certificate.ServerName)
|
||||
var hostnameToCheck string
|
||||
if len(matches) == 0 {
|
||||
|
|
@ -206,7 +206,7 @@ func (db *db) CreateRepoCertificate(ctx context.Context, certificates *appsv1.Re
|
|||
if !upsert && entry.Data != string(certificate.CertData) {
|
||||
return nil, fmt.Errorf("key for '%s' (subtype: '%s') already exists, and upsert was not specified", entry.Host, entry.SubType)
|
||||
}
|
||||
// Do not add an entry on upsert, but remember if we actual did an
|
||||
// Do not add an entry on upsert, but remember if we actually did an
|
||||
// upsert.
|
||||
newEntry = false
|
||||
if entry.Data != string(certificate.CertData) {
|
||||
|
|
@ -332,7 +332,7 @@ func (db *db) CreateRepoCertificate(ctx context.Context, certificates *appsv1.Re
|
|||
return &appsv1.RepositoryCertificateList{Items: created}, nil
|
||||
}
|
||||
|
||||
// Batch remove configured certificates according to the selector query
|
||||
// RemoveRepoCertificates removes configured certificates according to the selector query
|
||||
func (db *db) RemoveRepoCertificates(ctx context.Context, selector *CertificateListSelector) (*appsv1.RepositoryCertificateList, error) {
|
||||
var (
|
||||
knownHostsOld []*SSHKnownHostsEntry
|
||||
|
|
@ -376,7 +376,7 @@ func (db *db) RemoveRepoCertificates(ctx context.Context, selector *CertificateL
|
|||
for _, entry := range tlsCertificatesOld {
|
||||
if certutil.MatchHostName(entry.Subject, selector.HostNamePattern) {
|
||||
// Wrap each PEM certificate into its own RepositoryCertificate object
|
||||
// so the caller knows what has been removed actually.
|
||||
// so the caller knows what has actually been removed.
|
||||
//
|
||||
// The downside of this is, only valid data can be removed from the CM,
|
||||
// so if the data somehow got corrupted, it can only be removed by
|
||||
|
|
|
|||
|
|
@ -330,21 +330,25 @@ func secretToRepository(secret *corev1.Secret) (*appsv1.Repository, error) {
|
|||
secretCopy := secret.DeepCopy()
|
||||
|
||||
repository := &appsv1.Repository{
|
||||
Name: string(secretCopy.Data["name"]),
|
||||
Repo: string(secretCopy.Data["url"]),
|
||||
Username: string(secretCopy.Data["username"]),
|
||||
Password: string(secretCopy.Data["password"]),
|
||||
BearerToken: string(secretCopy.Data["bearerToken"]),
|
||||
SSHPrivateKey: string(secretCopy.Data["sshPrivateKey"]),
|
||||
TLSClientCertData: string(secretCopy.Data["tlsClientCertData"]),
|
||||
TLSClientCertKey: string(secretCopy.Data["tlsClientCertKey"]),
|
||||
Type: string(secretCopy.Data["type"]),
|
||||
GithubAppPrivateKey: string(secretCopy.Data["githubAppPrivateKey"]),
|
||||
GitHubAppEnterpriseBaseURL: string(secretCopy.Data["githubAppEnterpriseBaseUrl"]),
|
||||
Proxy: string(secretCopy.Data["proxy"]),
|
||||
NoProxy: string(secretCopy.Data["noProxy"]),
|
||||
Project: string(secretCopy.Data["project"]),
|
||||
GCPServiceAccountKey: string(secretCopy.Data["gcpServiceAccountKey"]),
|
||||
Name: string(secretCopy.Data["name"]),
|
||||
Repo: string(secretCopy.Data["url"]),
|
||||
Username: string(secretCopy.Data["username"]),
|
||||
Password: string(secretCopy.Data["password"]),
|
||||
BearerToken: string(secretCopy.Data["bearerToken"]),
|
||||
SSHPrivateKey: string(secretCopy.Data["sshPrivateKey"]),
|
||||
TLSClientCertData: string(secretCopy.Data["tlsClientCertData"]),
|
||||
TLSClientCertKey: string(secretCopy.Data["tlsClientCertKey"]),
|
||||
Type: string(secretCopy.Data["type"]),
|
||||
GithubAppPrivateKey: string(secretCopy.Data["githubAppPrivateKey"]),
|
||||
GitHubAppEnterpriseBaseURL: string(secretCopy.Data["githubAppEnterpriseBaseUrl"]),
|
||||
Proxy: string(secretCopy.Data["proxy"]),
|
||||
NoProxy: string(secretCopy.Data["noProxy"]),
|
||||
Project: string(secretCopy.Data["project"]),
|
||||
GCPServiceAccountKey: string(secretCopy.Data["gcpServiceAccountKey"]),
|
||||
AzureServicePrincipalClientId: string(secretCopy.Data["azureServicePrincipalClientId"]),
|
||||
AzureServicePrincipalClientSecret: string(secretCopy.Data["azureServicePrincipalClientSecret"]),
|
||||
AzureServicePrincipalTenantId: string(secretCopy.Data["azureServicePrincipalTenantId"]),
|
||||
AzureActiveDirectoryEndpoint: string(secretCopy.Data["azureActiveDirectoryEndpoint"]),
|
||||
}
|
||||
|
||||
insecureIgnoreHostKey, err := boolOrFalse(secretCopy, "insecureIgnoreHostKey")
|
||||
|
|
@ -451,6 +455,10 @@ func (s *secretsRepositoryBackend) repositoryToSecret(repository *appsv1.Reposit
|
|||
updateSecretBool(secretCopy, "useAzureWorkloadIdentity", repository.UseAzureWorkloadIdentity)
|
||||
updateSecretInt(secretCopy, "depth", repository.Depth)
|
||||
updateSecretBool(secretCopy, "webhookManifestCacheWarmDisabled", repository.WebhookManifestCacheWarmDisabled)
|
||||
updateSecretString(secretCopy, "azureServicePrincipalClientId", repository.AzureServicePrincipalClientId)
|
||||
updateSecretString(secretCopy, "azureServicePrincipalClientSecret", repository.AzureServicePrincipalClientSecret)
|
||||
updateSecretString(secretCopy, "azureServicePrincipalTenantId", repository.AzureServicePrincipalTenantId)
|
||||
updateSecretString(secretCopy, "azureActiveDirectoryEndpoint", repository.AzureActiveDirectoryEndpoint)
|
||||
addSecretMetadata(secretCopy, s.getSecretType())
|
||||
|
||||
return secretCopy
|
||||
|
|
@ -460,19 +468,23 @@ func (s *secretsRepositoryBackend) secretToRepoCred(secret *corev1.Secret) (*app
|
|||
secretCopy := secret.DeepCopy()
|
||||
|
||||
repository := &appsv1.RepoCreds{
|
||||
URL: string(secretCopy.Data["url"]),
|
||||
Username: string(secretCopy.Data["username"]),
|
||||
Password: string(secretCopy.Data["password"]),
|
||||
BearerToken: string(secretCopy.Data["bearerToken"]),
|
||||
SSHPrivateKey: string(secretCopy.Data["sshPrivateKey"]),
|
||||
TLSClientCertData: string(secretCopy.Data["tlsClientCertData"]),
|
||||
TLSClientCertKey: string(secretCopy.Data["tlsClientCertKey"]),
|
||||
Type: string(secretCopy.Data["type"]),
|
||||
GithubAppPrivateKey: string(secretCopy.Data["githubAppPrivateKey"]),
|
||||
GitHubAppEnterpriseBaseURL: string(secretCopy.Data["githubAppEnterpriseBaseUrl"]),
|
||||
GCPServiceAccountKey: string(secretCopy.Data["gcpServiceAccountKey"]),
|
||||
Proxy: string(secretCopy.Data["proxy"]),
|
||||
NoProxy: string(secretCopy.Data["noProxy"]),
|
||||
URL: string(secretCopy.Data["url"]),
|
||||
Username: string(secretCopy.Data["username"]),
|
||||
Password: string(secretCopy.Data["password"]),
|
||||
BearerToken: string(secretCopy.Data["bearerToken"]),
|
||||
SSHPrivateKey: string(secretCopy.Data["sshPrivateKey"]),
|
||||
TLSClientCertData: string(secretCopy.Data["tlsClientCertData"]),
|
||||
TLSClientCertKey: string(secretCopy.Data["tlsClientCertKey"]),
|
||||
Type: string(secretCopy.Data["type"]),
|
||||
GithubAppPrivateKey: string(secretCopy.Data["githubAppPrivateKey"]),
|
||||
GitHubAppEnterpriseBaseURL: string(secretCopy.Data["githubAppEnterpriseBaseUrl"]),
|
||||
GCPServiceAccountKey: string(secretCopy.Data["gcpServiceAccountKey"]),
|
||||
Proxy: string(secretCopy.Data["proxy"]),
|
||||
NoProxy: string(secretCopy.Data["noProxy"]),
|
||||
AzureServicePrincipalClientId: string(secretCopy.Data["azureServicePrincipalClientID"]),
|
||||
AzureServicePrincipalClientSecret: string(secretCopy.Data["azureServicePrincipalClientSecret"]),
|
||||
AzureServicePrincipalTenantId: string(secretCopy.Data["azureServicePrincipalTenantID"]),
|
||||
AzureActiveDirectoryEndpoint: string(secretCopy.Data["azureActiveDirectoryEndpoint"]),
|
||||
}
|
||||
|
||||
enableOCI, err := boolOrFalse(secretCopy, "enableOCI")
|
||||
|
|
@ -540,6 +552,10 @@ func (s *secretsRepositoryBackend) repoCredsToSecret(repoCreds *appsv1.RepoCreds
|
|||
updateSecretString(secretCopy, "noProxy", repoCreds.NoProxy)
|
||||
updateSecretBool(secretCopy, "forceHttpBasicAuth", repoCreds.ForceHttpBasicAuth)
|
||||
updateSecretBool(secretCopy, "useAzureWorkloadIdentity", repoCreds.UseAzureWorkloadIdentity)
|
||||
updateSecretString(secretCopy, "azureServicePrincipalClientID", repoCreds.AzureServicePrincipalClientId)
|
||||
updateSecretString(secretCopy, "azureServicePrincipalClientSecret", repoCreds.AzureServicePrincipalClientSecret)
|
||||
updateSecretString(secretCopy, "azureServicePrincipalTenantID", repoCreds.AzureServicePrincipalTenantId)
|
||||
updateSecretString(secretCopy, "azureActiveDirectoryEndpoint", repoCreds.AzureActiveDirectoryEndpoint)
|
||||
addSecretMetadata(secretCopy, s.getRepoCredSecretType())
|
||||
|
||||
return secretCopy
|
||||
|
|
|
|||
|
|
@ -412,6 +412,13 @@ func newAuth(repoURL string, creds Creds) (transport.AuthMethod, error) {
|
|||
return nil, fmt.Errorf("failed to get access token from creds: %w", err)
|
||||
}
|
||||
|
||||
auth := githttp.TokenAuth{Token: token}
|
||||
return &auth, nil
|
||||
case AzureServicePrincipalCreds:
|
||||
token, err := creds.getAccessToken()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get access token from creds: %w", err)
|
||||
}
|
||||
auth := githttp.TokenAuth{Token: token}
|
||||
return &auth, nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,6 +18,10 @@ import (
|
|||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/azcore"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/azcore/cloud"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/azcore/policy"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/azidentity"
|
||||
giturls "github.com/chainguard-dev/git-urls"
|
||||
"github.com/google/go-github/v69/github"
|
||||
|
||||
|
|
@ -50,6 +54,8 @@ var (
|
|||
// installationIdCache caches installation IDs for organizations to avoid redundant API calls.
|
||||
githubInstallationIdCache *gocache.Cache
|
||||
githubInstallationIdCacheMutex sync.RWMutex // For bulk API call coordination
|
||||
// In memory cache for storing Azure Service Principal tokens
|
||||
azureServicePrincipalTokenCache *gocache.Cache
|
||||
)
|
||||
|
||||
const (
|
||||
|
|
@ -64,16 +70,30 @@ const (
|
|||
func init() {
|
||||
githubAppCredsExp := common.GithubAppCredsExpirationDuration
|
||||
if exp := os.Getenv(common.EnvGithubAppCredsExpirationDuration); exp != "" {
|
||||
if qps, err := strconv.Atoi(exp); err != nil {
|
||||
if qps, err := strconv.Atoi(exp); err == nil {
|
||||
githubAppCredsExp = time.Duration(qps) * time.Minute
|
||||
}
|
||||
}
|
||||
azureServicePrincipalCredsExp := common.AzureServicePrincipalCredsExpirationDuration
|
||||
if exp := os.Getenv(common.EnvAzureServicePrincipalCredsExpirationDuration); exp != "" {
|
||||
if qps, err := strconv.Atoi(exp); err == nil {
|
||||
// Azure service principal tokens are valid for 60 minutes
|
||||
// the cache has a cleanup interval of 1 minute
|
||||
// cap the expiration duration to 59 minutes to avoid issues with token expiration
|
||||
if qps > 59 {
|
||||
log.Warnf("Value in %s is %d, which is greater than maximum 59 minutes allowed. Setting to 59 minutes", common.EnvAzureServicePrincipalCredsExpirationDuration, qps)
|
||||
qps = 59
|
||||
}
|
||||
azureServicePrincipalCredsExp = time.Duration(qps) * time.Minute
|
||||
}
|
||||
}
|
||||
|
||||
githubAppTokenCache = gocache.New(githubAppCredsExp, 1*time.Minute)
|
||||
// oauth2.TokenSource handles fetching new Tokens once they are expired. The oauth2.TokenSource itself does not expire.
|
||||
googleCloudTokenSource = gocache.New(gocache.NoExpiration, 0)
|
||||
azureTokenCache = gocache.New(gocache.NoExpiration, 0)
|
||||
githubInstallationIdCache = gocache.New(60*time.Minute, 60*time.Minute)
|
||||
azureServicePrincipalTokenCache = gocache.New(azureServicePrincipalCredsExp, 1*time.Minute)
|
||||
}
|
||||
|
||||
type NoopCredsStore struct{}
|
||||
|
|
@ -974,3 +994,133 @@ func (creds AzureWorkloadIdentityCreds) GetAzureDevOpsAccessToken() (string, err
|
|||
accessToken, err := creds.getAccessToken(azureDevopsEntraResourceId) // wellknown resourceid of Azure DevOps
|
||||
return accessToken, err
|
||||
}
|
||||
|
||||
var _ Creds = AzureServicePrincipalCreds{}
|
||||
|
||||
// AzureServicePrincipalCreds to authenticate to Azure DevOps using a Service Principal
|
||||
type AzureServicePrincipalCreds struct {
|
||||
tenantID string
|
||||
clientID string
|
||||
clientSecret string
|
||||
activeDirectoryEndpoint string
|
||||
clientCertData string
|
||||
clientCertKey string
|
||||
proxy string
|
||||
noProxy string
|
||||
store CredsStore
|
||||
}
|
||||
|
||||
// NewAzureServicePrincipalCreds creates new Azure Service Principal credentials
|
||||
func NewAzureServicePrincipalCreds(tenantID string, clientID string, clientSecret string, store CredsStore) AzureServicePrincipalCreds {
|
||||
return AzureServicePrincipalCreds{tenantID: tenantID, clientID: clientID, clientSecret: clientSecret, store: store}
|
||||
}
|
||||
|
||||
// WithActiveDirectoryEndpoint sets a custom Active Directory endpoint. When not set, the default Azure public cloud is used.
|
||||
func (a AzureServicePrincipalCreds) WithActiveDirectoryEndpoint(activeDirectoryEndpoint string) AzureServicePrincipalCreds {
|
||||
if activeDirectoryEndpoint != "" {
|
||||
a.activeDirectoryEndpoint = activeDirectoryEndpoint
|
||||
}
|
||||
return a
|
||||
}
|
||||
|
||||
// WithClientCert sets the client certificate data and key
|
||||
func (a AzureServicePrincipalCreds) WithClientCert(data string, key string) AzureServicePrincipalCreds {
|
||||
if data != "" && key != "" {
|
||||
a.clientCertData = data
|
||||
a.clientCertKey = key
|
||||
}
|
||||
return a
|
||||
}
|
||||
|
||||
// WithProxy sets the HTTP/HTTPS proxy used to access the repo
|
||||
func (a AzureServicePrincipalCreds) WithProxy(proxy string) AzureServicePrincipalCreds {
|
||||
if proxy != "" {
|
||||
a.proxy = proxy
|
||||
}
|
||||
return a
|
||||
}
|
||||
|
||||
// WithNoProxy sets a comma separated list of IPs/hostnames that should not use the proxy
|
||||
func (a AzureServicePrincipalCreds) WithNoProxy(noProxy string) AzureServicePrincipalCreds {
|
||||
if noProxy != "" {
|
||||
a.noProxy = noProxy
|
||||
}
|
||||
return a
|
||||
}
|
||||
|
||||
// GetUserInfo doesn't return any user info as they are not present for Azure Service Principals.
|
||||
func (a AzureServicePrincipalCreds) GetUserInfo(_ context.Context) (string, string, error) {
|
||||
return workloadidentity.EmptyGuid, "", nil
|
||||
}
|
||||
|
||||
func (a AzureServicePrincipalCreds) Environ() (io.Closer, []string, error) {
|
||||
token, err := a.getAccessToken()
|
||||
if err != nil {
|
||||
return NopCloser{}, nil, err
|
||||
}
|
||||
nonce := a.store.Add("", token)
|
||||
env := a.store.Environ(nonce)
|
||||
env = append(env, fmt.Sprintf("%s=Authorization: Bearer %s", bearerAuthHeaderEnv, token))
|
||||
|
||||
return utilio.NewCloser(func() error {
|
||||
a.store.Remove(nonce)
|
||||
return nil
|
||||
}), env, nil
|
||||
}
|
||||
|
||||
func (a AzureServicePrincipalCreds) getAccessToken() (string, error) {
|
||||
// Override the default active directory endpoint if present
|
||||
activeDirectoryEndpoint := "https://login.microsoftonline.com"
|
||||
disableInstanceDiscovery := false
|
||||
if a.activeDirectoryEndpoint != "" {
|
||||
activeDirectoryEndpoint = a.activeDirectoryEndpoint
|
||||
disableInstanceDiscovery = true
|
||||
}
|
||||
|
||||
// Generate cache key for creds
|
||||
key, err := argoutils.GenerateCacheKey("%s %s %s %s", a.tenantID, a.clientID, a.clientSecret, activeDirectoryEndpoint)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to get get SHA256 hash for Azure Service Principal credentials: %w", err)
|
||||
}
|
||||
|
||||
t, found := azureServicePrincipalTokenCache.Get(key)
|
||||
if found {
|
||||
return t.(string), nil
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second)
|
||||
defer cancel()
|
||||
|
||||
opts := azcore.ClientOptions{}
|
||||
opts.Cloud = cloud.Configuration{
|
||||
ActiveDirectoryAuthorityHost: activeDirectoryEndpoint,
|
||||
}
|
||||
// Configure HTTP client with proxy if proxy is set
|
||||
if a.proxy != "" {
|
||||
opts.Transport = GetRepoHTTPClient(activeDirectoryEndpoint, false, a, a.proxy, a.noProxy)
|
||||
}
|
||||
cred, err := azidentity.NewClientSecretCredential(a.tenantID, a.clientID, a.clientSecret, &azidentity.ClientSecretCredentialOptions{ClientOptions: opts, DisableInstanceDiscovery: disableInstanceDiscovery})
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to create Azure client secret credential: %w", err)
|
||||
}
|
||||
token, err := cred.GetToken(ctx, policy.TokenRequestOptions{
|
||||
Scopes: []string{azureDevopsEntraResourceId},
|
||||
})
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to get Azure access token: %w", err)
|
||||
}
|
||||
azureServicePrincipalTokenCache.Set(key, token.Token, 0)
|
||||
return token.Token, nil
|
||||
}
|
||||
|
||||
func (a AzureServicePrincipalCreds) HasClientCert() bool {
|
||||
return a.clientCertData != "" && a.clientCertKey != ""
|
||||
}
|
||||
|
||||
func (a AzureServicePrincipalCreds) GetClientCertData() string {
|
||||
return a.clientCertData
|
||||
}
|
||||
|
||||
func (a AzureServicePrincipalCreds) GetClientCertKey() string {
|
||||
return a.clientCertKey
|
||||
}
|
||||
|
|
|
|||
|
|
@ -719,7 +719,7 @@ entries: {}
|
|||
|
||||
// Should succeed because our implementation sets User-Agent
|
||||
require.NoError(t, err, "Request should succeed with User-Agent set")
|
||||
t.Logf("Success! Server accepted request with User-Agent")
|
||||
t.Log("Success! Server accepted request with User-Agent")
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -326,6 +326,14 @@ type Repository struct {
|
|||
ForceHttpBasicAuth bool `json:"forceHttpBasicAuth,omitempty"` //nolint:revive //FIXME(var-naming)
|
||||
// UseAzureWorkloadIdentity specifies whether to use Azure Workload Identity for authentication
|
||||
UseAzureWorkloadIdentity bool `json:"useAzureWorkloadIdentity,omitempty"`
|
||||
// AzureActiveDirectoryEndpoint specifies the Azure Active Directory endpoint used for Service Principal authentication. If empty will default to https://login.microsoftonline.com
|
||||
AzureActiveDirectoryEndpoint string `json:"azureActiveDirectoryEndpoint,omitempty"`
|
||||
// AzureServicePrincipalClientId specifies the client ID of the Azure Service Principal used to access the repo
|
||||
AzureServicePrincipalClientId string `json:"azureServicePrincipalClientId,omitempty"`
|
||||
// AzureServicePrincipalClientSecret specifies the client secret of the Azure Service Principal used to access the repo
|
||||
AzureServicePrincipalClientSecret string `json:"azureServicePrincipalClientSecret,omitempty"`
|
||||
// AzureServicePrincipalTenantId specifies the tenant ID of the Azure Service Principal used to access the repo
|
||||
AzureServicePrincipalTenantId string `json:"azureServicePrincipalTenantId,omitempty"`
|
||||
}
|
||||
|
||||
// Credential template for accessing repositories
|
||||
|
|
@ -360,6 +368,14 @@ type RepositoryCredentials struct {
|
|||
ForceHttpBasicAuth bool `json:"forceHttpBasicAuth,omitempty"` //nolint:revive //FIXME(var-naming)
|
||||
// UseAzureWorkloadIdentity specifies whether to use Azure Workload Identity for authentication
|
||||
UseAzureWorkloadIdentity bool `json:"useAzureWorkloadIdentity,omitempty"`
|
||||
// AzureActiveDirectoryEndpoint specifies the Azure Active Directory endpoint used for Service Principal authentication. If empty will default to https://login.microsoftonline.com
|
||||
AzureActiveDirectoryEndpoint string `json:"azureActiveDirectoryEndpoint,omitempty"`
|
||||
// AzureServicePrincipalClientId specifies the client ID of the Azure Service Principal used to access the repo
|
||||
AzureServicePrincipalClientId string `json:"azureServicePrincipalClientId,omitempty"`
|
||||
// AzureServicePrincipalClientSecret specifies the client secret of the Azure Service Principal used to access the repo
|
||||
AzureServicePrincipalClientSecret string `json:"azureServicePrincipalClientSecret,omitempty"`
|
||||
// AzureServicePrincipalTenantId specifies the tenant ID of the Azure Service Principal used to access the repo
|
||||
AzureServicePrincipalTenantId string `json:"azureServicePrincipalTenantId,omitempty"`
|
||||
}
|
||||
|
||||
// DeepLink structure
|
||||
|
|
|
|||
|
|
@ -139,7 +139,7 @@ func getTLSConfigCustomizer(minVersionStr, maxVersionStr, tlsCiphersStr string)
|
|||
}
|
||||
|
||||
if tlsCiphersStr == "list" {
|
||||
fmt.Printf("Supported TLS ciphers:\n")
|
||||
fmt.Print("Supported TLS ciphers:\n")
|
||||
for _, s := range tls.CipherSuites() {
|
||||
fmt.Printf("* %s (TLS versions: %s)\n", tls.CipherSuiteName(s.ID), strings.Join(tlsVersionsToStr(s.SupportedVersions), ", "))
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue