mirror of
https://github.com/fluxcd/flux2.git
synced 2025-10-29 15:28:04 +08:00
Add safe guards for relative paths
This commit adds multiple safe guards for relative paths, ensuring they never traverse outside the working directory. The `SafeRelativePath` flag calculates the safe relative path based on a relative base dir, which results in a flattened path. The write methods of `manifestgen` make use of the `SecureJoin` as well, to ensure writes are never outside of the given directory when used as a lib outside of the CLI. Signed-off-by: Hidde Beydals <hello@hidde.co>
This commit is contained in:
@ -135,12 +135,11 @@ func generateInstallManifests(targetPath, namespace, tmpDir string, localManifes
|
|||||||
return "", fmt.Errorf("generating install manifests failed: %w", err)
|
return "", fmt.Errorf("generating install manifests failed: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if filePath, err := output.WriteFile(tmpDir); err != nil {
|
filePath, err := output.WriteFile(tmpDir)
|
||||||
|
if err != nil {
|
||||||
return "", fmt.Errorf("generating install manifests failed: %w", err)
|
return "", fmt.Errorf("generating install manifests failed: %w", err)
|
||||||
} else {
|
|
||||||
return filePath, nil
|
|
||||||
}
|
}
|
||||||
|
return filePath, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func applyInstallManifests(ctx context.Context, manifestPath string, components []string) error {
|
func applyInstallManifests(ctx context.Context, manifestPath string, components []string) error {
|
||||||
@ -158,7 +157,7 @@ func applyInstallManifests(ctx context.Context, manifestPath string, components
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func generateSyncManifests(url, branch, name, namespace, targetPath, tmpDir string, interval time.Duration) error {
|
func generateSyncManifests(url, branch, name, namespace, targetPath, tmpDir string, interval time.Duration) (string, error) {
|
||||||
opts := sync.Options{
|
opts := sync.Options{
|
||||||
Name: name,
|
Name: name,
|
||||||
Namespace: namespace,
|
Namespace: namespace,
|
||||||
@ -171,22 +170,22 @@ func generateSyncManifests(url, branch, name, namespace, targetPath, tmpDir stri
|
|||||||
|
|
||||||
manifest, err := sync.Generate(opts)
|
manifest, err := sync.Generate(opts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("generating install manifests failed: %w", err)
|
return "", fmt.Errorf("generating install manifests failed: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, err := manifest.WriteFile(tmpDir); err != nil {
|
output, err := manifest.WriteFile(tmpDir)
|
||||||
return err
|
if err != nil {
|
||||||
|
return "", err
|
||||||
}
|
}
|
||||||
|
outputDir := filepath.Dir(output)
|
||||||
if err := utils.GenerateKustomizationYaml(filepath.Join(tmpDir, targetPath, namespace)); err != nil {
|
if err := utils.GenerateKustomizationYaml(outputDir); err != nil {
|
||||||
return err
|
return "", err
|
||||||
}
|
}
|
||||||
|
return outputDir, nil
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func applySyncManifests(ctx context.Context, kubeClient client.Client, name, namespace, targetPath, tmpDir string) error {
|
func applySyncManifests(ctx context.Context, kubeClient client.Client, name, namespace, manifestsPath string) error {
|
||||||
kubectlArgs := []string{"apply", "-k", filepath.Join(tmpDir, targetPath, namespace)}
|
kubectlArgs := []string{"apply", "-k", manifestsPath}
|
||||||
if _, err := utils.ExecKubectlCommand(ctx, utils.ModeStderrOS, kubeconfig, kubecontext, kubectlArgs...); err != nil {
|
if _, err := utils.ExecKubectlCommand(ctx, utils.ModeStderrOS, kubeconfig, kubecontext, kubectlArgs...); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@ -29,8 +29,10 @@ import (
|
|||||||
corev1 "k8s.io/api/core/v1"
|
corev1 "k8s.io/api/core/v1"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
|
||||||
"github.com/fluxcd/flux2/internal/utils"
|
|
||||||
"github.com/fluxcd/pkg/git"
|
"github.com/fluxcd/pkg/git"
|
||||||
|
|
||||||
|
"github.com/fluxcd/flux2/internal/flags"
|
||||||
|
"github.com/fluxcd/flux2/internal/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
var bootstrapGitHubCmd = &cobra.Command{
|
var bootstrapGitHubCmd = &cobra.Command{
|
||||||
@ -75,7 +77,7 @@ var (
|
|||||||
ghPersonal bool
|
ghPersonal bool
|
||||||
ghPrivate bool
|
ghPrivate bool
|
||||||
ghHostname string
|
ghHostname string
|
||||||
ghPath string
|
ghPath flags.SafeRelativePath
|
||||||
ghTeams []string
|
ghTeams []string
|
||||||
ghDelete bool
|
ghDelete bool
|
||||||
ghSSHHostname string
|
ghSSHHostname string
|
||||||
@ -94,7 +96,7 @@ func init() {
|
|||||||
bootstrapGitHubCmd.Flags().DurationVar(&ghInterval, "interval", time.Minute, "sync interval")
|
bootstrapGitHubCmd.Flags().DurationVar(&ghInterval, "interval", time.Minute, "sync interval")
|
||||||
bootstrapGitHubCmd.Flags().StringVar(&ghHostname, "hostname", git.GitHubDefaultHostname, "GitHub hostname")
|
bootstrapGitHubCmd.Flags().StringVar(&ghHostname, "hostname", git.GitHubDefaultHostname, "GitHub hostname")
|
||||||
bootstrapGitHubCmd.Flags().StringVar(&ghSSHHostname, "ssh-hostname", "", "GitHub SSH hostname, to be used when the SSH host differs from the HTTPS one")
|
bootstrapGitHubCmd.Flags().StringVar(&ghSSHHostname, "ssh-hostname", "", "GitHub SSH hostname, to be used when the SSH host differs from the HTTPS one")
|
||||||
bootstrapGitHubCmd.Flags().StringVar(&ghPath, "path", "", "repository path, when specified the cluster sync will be scoped to this path")
|
bootstrapGitHubCmd.Flags().Var(&ghPath, "path", "path relative to the repository root, when specified the cluster sync will be scoped to this path")
|
||||||
|
|
||||||
bootstrapGitHubCmd.Flags().BoolVar(&ghDelete, "delete", false, "delete repository (used for testing only)")
|
bootstrapGitHubCmd.Flags().BoolVar(&ghDelete, "delete", false, "delete repository (used for testing only)")
|
||||||
bootstrapGitHubCmd.Flags().MarkHidden("delete")
|
bootstrapGitHubCmd.Flags().MarkHidden("delete")
|
||||||
@ -174,13 +176,13 @@ func bootstrapGitHubCmdRun(cmd *cobra.Command, args []string) error {
|
|||||||
|
|
||||||
// generate install manifests
|
// generate install manifests
|
||||||
logger.Generatef("generating manifests")
|
logger.Generatef("generating manifests")
|
||||||
manifest, err := generateInstallManifests(ghPath, namespace, tmpDir, bootstrapManifestsPath)
|
installManifest, err := generateInstallManifests(ghPath.String(), namespace, tmpDir, bootstrapManifestsPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// stage install manifests
|
// stage install manifests
|
||||||
changed, err = repository.Commit(ctx, path.Join(ghPath, namespace), "Add manifests")
|
changed, err = repository.Commit(ctx, path.Join(ghPath.String(), namespace), "Add manifests")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -206,7 +208,7 @@ func bootstrapGitHubCmdRun(cmd *cobra.Command, args []string) error {
|
|||||||
if isInstall {
|
if isInstall {
|
||||||
// apply install manifests
|
// apply install manifests
|
||||||
logger.Actionf("installing components in %s namespace", namespace)
|
logger.Actionf("installing components in %s namespace", namespace)
|
||||||
if err := applyInstallManifests(ctx, manifest, bootstrapComponents()); err != nil {
|
if err := applyInstallManifests(ctx, installManifest, bootstrapComponents()); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
logger.Successf("install completed")
|
logger.Successf("install completed")
|
||||||
@ -259,12 +261,13 @@ func bootstrapGitHubCmdRun(cmd *cobra.Command, args []string) error {
|
|||||||
|
|
||||||
// configure repo synchronization
|
// configure repo synchronization
|
||||||
logger.Actionf("generating sync manifests")
|
logger.Actionf("generating sync manifests")
|
||||||
if err := generateSyncManifests(repoURL, bootstrapBranch, namespace, namespace, ghPath, tmpDir, ghInterval); err != nil {
|
syncManifests, err := generateSyncManifests(repoURL, bootstrapBranch, namespace, namespace, ghPath.String(), tmpDir, ghInterval)
|
||||||
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// commit and push manifests
|
// commit and push manifests
|
||||||
if changed, err = repository.Commit(ctx, path.Join(ghPath, namespace), "Add manifests"); err != nil {
|
if changed, err = repository.Commit(ctx, path.Join(ghPath.String(), namespace), "Add manifests"); err != nil {
|
||||||
return err
|
return err
|
||||||
} else if changed {
|
} else if changed {
|
||||||
if err := repository.Push(ctx); err != nil {
|
if err := repository.Push(ctx); err != nil {
|
||||||
@ -275,7 +278,7 @@ func bootstrapGitHubCmdRun(cmd *cobra.Command, args []string) error {
|
|||||||
|
|
||||||
// apply manifests and waiting for sync
|
// apply manifests and waiting for sync
|
||||||
logger.Actionf("applying sync manifests")
|
logger.Actionf("applying sync manifests")
|
||||||
if err := applySyncManifests(ctx, kubeClient, namespace, namespace, ghPath, tmpDir); err != nil {
|
if err := applySyncManifests(ctx, kubeClient, namespace, namespace, syncManifests); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -29,8 +29,10 @@ import (
|
|||||||
corev1 "k8s.io/api/core/v1"
|
corev1 "k8s.io/api/core/v1"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
|
||||||
"github.com/fluxcd/flux2/internal/utils"
|
|
||||||
"github.com/fluxcd/pkg/git"
|
"github.com/fluxcd/pkg/git"
|
||||||
|
|
||||||
|
"github.com/fluxcd/flux2/internal/flags"
|
||||||
|
"github.com/fluxcd/flux2/internal/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
var bootstrapGitLabCmd = &cobra.Command{
|
var bootstrapGitLabCmd = &cobra.Command{
|
||||||
@ -73,7 +75,7 @@ var (
|
|||||||
glPrivate bool
|
glPrivate bool
|
||||||
glHostname string
|
glHostname string
|
||||||
glSSHHostname string
|
glSSHHostname string
|
||||||
glPath string
|
glPath flags.SafeRelativePath
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
@ -84,7 +86,7 @@ func init() {
|
|||||||
bootstrapGitLabCmd.Flags().DurationVar(&glInterval, "interval", time.Minute, "sync interval")
|
bootstrapGitLabCmd.Flags().DurationVar(&glInterval, "interval", time.Minute, "sync interval")
|
||||||
bootstrapGitLabCmd.Flags().StringVar(&glHostname, "hostname", git.GitLabDefaultHostname, "GitLab hostname")
|
bootstrapGitLabCmd.Flags().StringVar(&glHostname, "hostname", git.GitLabDefaultHostname, "GitLab hostname")
|
||||||
bootstrapGitLabCmd.Flags().StringVar(&glSSHHostname, "ssh-hostname", "", "GitLab SSH hostname, to be used when the SSH host differs from the HTTPS one")
|
bootstrapGitLabCmd.Flags().StringVar(&glSSHHostname, "ssh-hostname", "", "GitLab SSH hostname, to be used when the SSH host differs from the HTTPS one")
|
||||||
bootstrapGitLabCmd.Flags().StringVar(&glPath, "path", "", "repository path, when specified the cluster sync will be scoped to this path")
|
bootstrapGitLabCmd.Flags().Var(&glPath, "path", "path relative to the repository root, when specified the cluster sync will be scoped to this path")
|
||||||
|
|
||||||
bootstrapCmd.AddCommand(bootstrapGitLabCmd)
|
bootstrapCmd.AddCommand(bootstrapGitLabCmd)
|
||||||
}
|
}
|
||||||
@ -145,13 +147,13 @@ func bootstrapGitLabCmdRun(cmd *cobra.Command, args []string) error {
|
|||||||
|
|
||||||
// generate install manifests
|
// generate install manifests
|
||||||
logger.Generatef("generating manifests")
|
logger.Generatef("generating manifests")
|
||||||
manifest, err := generateInstallManifests(glPath, namespace, tmpDir, bootstrapManifestsPath)
|
installManifest, err := generateInstallManifests(glPath.String(), namespace, tmpDir, bootstrapManifestsPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// stage install manifests
|
// stage install manifests
|
||||||
changed, err = repository.Commit(ctx, path.Join(glPath, namespace), "Add manifests")
|
changed, err = repository.Commit(ctx, path.Join(glPath.String(), namespace), "Add manifests")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -172,7 +174,7 @@ func bootstrapGitLabCmdRun(cmd *cobra.Command, args []string) error {
|
|||||||
if isInstall {
|
if isInstall {
|
||||||
// apply install manifests
|
// apply install manifests
|
||||||
logger.Actionf("installing components in %s namespace", namespace)
|
logger.Actionf("installing components in %s namespace", namespace)
|
||||||
if err := applyInstallManifests(ctx, manifest, bootstrapComponents()); err != nil {
|
if err := applyInstallManifests(ctx, installManifest, bootstrapComponents()); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
logger.Successf("install completed")
|
logger.Successf("install completed")
|
||||||
@ -225,12 +227,13 @@ func bootstrapGitLabCmdRun(cmd *cobra.Command, args []string) error {
|
|||||||
|
|
||||||
// configure repo synchronization
|
// configure repo synchronization
|
||||||
logger.Actionf("generating sync manifests")
|
logger.Actionf("generating sync manifests")
|
||||||
if err := generateSyncManifests(repoURL, bootstrapBranch, namespace, namespace, glPath, tmpDir, glInterval); err != nil {
|
syncManifests, err := generateSyncManifests(repoURL, bootstrapBranch, namespace, namespace, glPath.String(), tmpDir, glInterval)
|
||||||
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// commit and push manifests
|
// commit and push manifests
|
||||||
if changed, err = repository.Commit(ctx, path.Join(glPath, namespace), "Add manifests"); err != nil {
|
if changed, err = repository.Commit(ctx, path.Join(glPath.String(), namespace), "Add manifests"); err != nil {
|
||||||
return err
|
return err
|
||||||
} else if changed {
|
} else if changed {
|
||||||
if err := repository.Push(ctx); err != nil {
|
if err := repository.Push(ctx); err != nil {
|
||||||
@ -241,7 +244,7 @@ func bootstrapGitLabCmdRun(cmd *cobra.Command, args []string) error {
|
|||||||
|
|
||||||
// apply manifests and waiting for sync
|
// apply manifests and waiting for sync
|
||||||
logger.Actionf("applying sync manifests")
|
logger.Actionf("applying sync manifests")
|
||||||
if err := applySyncManifests(ctx, kubeClient, namespace, namespace, glPath, tmpDir); err != nil {
|
if err := applySyncManifests(ctx, kubeClient, namespace, namespace, syncManifests); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -74,7 +74,7 @@ var createKsCmd = &cobra.Command{
|
|||||||
|
|
||||||
var (
|
var (
|
||||||
ksSource flags.KustomizationSource
|
ksSource flags.KustomizationSource
|
||||||
ksPath string
|
ksPath flags.SafeRelativePath = "./"
|
||||||
ksPrune bool
|
ksPrune bool
|
||||||
ksDependsOn []string
|
ksDependsOn []string
|
||||||
ksValidation string
|
ksValidation string
|
||||||
@ -88,7 +88,7 @@ var (
|
|||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
createKsCmd.Flags().Var(&ksSource, "source", ksSource.Description())
|
createKsCmd.Flags().Var(&ksSource, "source", ksSource.Description())
|
||||||
createKsCmd.Flags().StringVar(&ksPath, "path", "./", "path to the directory containing a kustomization.yaml file")
|
createKsCmd.Flags().Var(&ksPath, "path", "path to the directory containing a kustomization.yaml file")
|
||||||
createKsCmd.Flags().BoolVar(&ksPrune, "prune", false, "enable garbage collection")
|
createKsCmd.Flags().BoolVar(&ksPrune, "prune", false, "enable garbage collection")
|
||||||
createKsCmd.Flags().StringArrayVar(&ksHealthCheck, "health-check", nil, "workload to be included in the health assessment, in the format '<kind>/<name>.<namespace>'")
|
createKsCmd.Flags().StringArrayVar(&ksHealthCheck, "health-check", nil, "workload to be included in the health assessment, in the format '<kind>/<name>.<namespace>'")
|
||||||
createKsCmd.Flags().DurationVar(&ksHealthTimeout, "health-check-timeout", 2*time.Minute, "timeout of health checking operations")
|
createKsCmd.Flags().DurationVar(&ksHealthTimeout, "health-check-timeout", 2*time.Minute, "timeout of health checking operations")
|
||||||
@ -110,7 +110,7 @@ func createKsCmdRun(cmd *cobra.Command, args []string) error {
|
|||||||
if ksPath == "" {
|
if ksPath == "" {
|
||||||
return fmt.Errorf("path is required")
|
return fmt.Errorf("path is required")
|
||||||
}
|
}
|
||||||
if !strings.HasPrefix(ksPath, "./") {
|
if !strings.HasPrefix(ksPath.String(), "./") {
|
||||||
return fmt.Errorf("path must begin with ./")
|
return fmt.Errorf("path must begin with ./")
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -134,7 +134,7 @@ func createKsCmdRun(cmd *cobra.Command, args []string) error {
|
|||||||
Interval: metav1.Duration{
|
Interval: metav1.Duration{
|
||||||
Duration: interval,
|
Duration: interval,
|
||||||
},
|
},
|
||||||
Path: ksPath,
|
Path: ksPath.String(),
|
||||||
Prune: ksPrune,
|
Prune: ksPrune,
|
||||||
SourceRef: kustomizev1.CrossNamespaceSourceReference{
|
SourceRef: kustomizev1.CrossNamespaceSourceReference{
|
||||||
Kind: ksSource.Kind,
|
Kind: ksSource.Kind,
|
||||||
|
|||||||
@ -46,16 +46,16 @@ flux bootstrap github [flags]
|
|||||||
### Options
|
### Options
|
||||||
|
|
||||||
```
|
```
|
||||||
-h, --help help for github
|
-h, --help help for github
|
||||||
--hostname string GitHub hostname (default "github.com")
|
--hostname string GitHub hostname (default "github.com")
|
||||||
--interval duration sync interval (default 1m0s)
|
--interval duration sync interval (default 1m0s)
|
||||||
--owner string GitHub user or organization name
|
--owner string GitHub user or organization name
|
||||||
--path string repository path, when specified the cluster sync will be scoped to this path
|
--path safeRelativePath path relative to the repository root, when specified the cluster sync will be scoped to this path
|
||||||
--personal is personal repository
|
--personal is personal repository
|
||||||
--private is private repository (default true)
|
--private is private repository (default true)
|
||||||
--repository string GitHub repository name
|
--repository string GitHub repository name
|
||||||
--ssh-hostname string GitHub SSH hostname, to be used when the SSH host differs from the HTTPS one
|
--ssh-hostname string GitHub SSH hostname, to be used when the SSH host differs from the HTTPS one
|
||||||
--team stringArray GitHub team to be given maintainer access
|
--team stringArray GitHub team to be given maintainer access
|
||||||
```
|
```
|
||||||
|
|
||||||
### Options inherited from parent commands
|
### Options inherited from parent commands
|
||||||
|
|||||||
@ -43,15 +43,15 @@ flux bootstrap gitlab [flags]
|
|||||||
### Options
|
### Options
|
||||||
|
|
||||||
```
|
```
|
||||||
-h, --help help for gitlab
|
-h, --help help for gitlab
|
||||||
--hostname string GitLab hostname (default "gitlab.com")
|
--hostname string GitLab hostname (default "gitlab.com")
|
||||||
--interval duration sync interval (default 1m0s)
|
--interval duration sync interval (default 1m0s)
|
||||||
--owner string GitLab user or group name
|
--owner string GitLab user or group name
|
||||||
--path string repository path, when specified the cluster sync will be scoped to this path
|
--path safeRelativePath path relative to the repository root, when specified the cluster sync will be scoped to this path
|
||||||
--personal is personal repository
|
--personal is personal repository
|
||||||
--private is private repository (default true)
|
--private is private repository (default true)
|
||||||
--repository string GitLab repository name
|
--repository string GitLab repository name
|
||||||
--ssh-hostname string GitLab SSH hostname, to be used when the SSH host differs from the HTTPS one
|
--ssh-hostname string GitLab SSH hostname, to be used when the SSH host differs from the HTTPS one
|
||||||
```
|
```
|
||||||
|
|
||||||
### Options inherited from parent commands
|
### Options inherited from parent commands
|
||||||
|
|||||||
@ -50,7 +50,7 @@ flux create kustomization [name] [flags]
|
|||||||
--health-check stringArray workload to be included in the health assessment, in the format '<kind>/<name>.<namespace>'
|
--health-check stringArray workload to be included in the health assessment, in the format '<kind>/<name>.<namespace>'
|
||||||
--health-check-timeout duration timeout of health checking operations (default 2m0s)
|
--health-check-timeout duration timeout of health checking operations (default 2m0s)
|
||||||
-h, --help help for kustomization
|
-h, --help help for kustomization
|
||||||
--path string path to the directory containing a kustomization.yaml file (default "./")
|
--path safeRelativePath path to the directory containing a kustomization.yaml file (default ./)
|
||||||
--prune enable garbage collection
|
--prune enable garbage collection
|
||||||
--service-account string the name of the service account to impersonate when reconciling this Kustomization
|
--service-account string the name of the service account to impersonate when reconciling this Kustomization
|
||||||
--source kustomizationSource source that contains the Kubernetes manifests in the format '[<kind>/]<name>',where kind can be one of: (GitRepository, Bucket), if kind is not specified it defaults to GitRepository
|
--source kustomizationSource source that contains the Kubernetes manifests in the format '[<kind>/]<name>',where kind can be one of: (GitRepository, Bucket), if kind is not specified it defaults to GitRepository
|
||||||
|
|||||||
1
go.mod
1
go.mod
@ -4,6 +4,7 @@ go 1.15
|
|||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/blang/semver/v4 v4.0.0
|
github.com/blang/semver/v4 v4.0.0
|
||||||
|
github.com/cyphar/filepath-securejoin v0.2.2
|
||||||
github.com/fluxcd/helm-controller/api v0.4.3
|
github.com/fluxcd/helm-controller/api v0.4.3
|
||||||
github.com/fluxcd/image-automation-controller/api v0.1.0
|
github.com/fluxcd/image-automation-controller/api v0.1.0
|
||||||
github.com/fluxcd/image-reflector-controller/api v0.1.0
|
github.com/fluxcd/image-reflector-controller/api v0.1.0
|
||||||
|
|||||||
9
go.sum
9
go.sum
@ -6,7 +6,6 @@ cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxK
|
|||||||
cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=
|
cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=
|
||||||
cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=
|
cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=
|
||||||
cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To=
|
cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To=
|
||||||
cloud.google.com/go v0.51.0 h1:PvKAVQWCtlGUSlZkGW3QLelKaWq7KYv/MW1EboG8bfM=
|
|
||||||
cloud.google.com/go v0.51.0/go.mod h1:hWtGJ6gnXH+KgDv+V0zFGDvpi07n3z8ZNj3T1RW0Gcw=
|
cloud.google.com/go v0.51.0/go.mod h1:hWtGJ6gnXH+KgDv+V0zFGDvpi07n3z8ZNj3T1RW0Gcw=
|
||||||
cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4=
|
cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4=
|
||||||
cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M=
|
cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M=
|
||||||
@ -33,24 +32,20 @@ github.com/Azure/go-autorest v14.2.0+incompatible h1:V5VMDjClD3GiElqLWO7mz2MxNAK
|
|||||||
github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24=
|
github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24=
|
||||||
github.com/Azure/go-autorest/autorest v0.9.0/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI=
|
github.com/Azure/go-autorest/autorest v0.9.0/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI=
|
||||||
github.com/Azure/go-autorest/autorest v0.9.3/go.mod h1:GsRuLYvwzLjjjRoWEIyMUaYq8GNUx2nRB378IPt/1p0=
|
github.com/Azure/go-autorest/autorest v0.9.3/go.mod h1:GsRuLYvwzLjjjRoWEIyMUaYq8GNUx2nRB378IPt/1p0=
|
||||||
github.com/Azure/go-autorest/autorest v0.9.6 h1:5YWtOnckcudzIw8lPPBcWOnmIFWMtHci1ZWAZulMSx0=
|
|
||||||
github.com/Azure/go-autorest/autorest v0.9.6/go.mod h1:/FALq9T/kS7b5J5qsQ+RSTUdAmGFqi0vUdVNNx8q630=
|
github.com/Azure/go-autorest/autorest v0.9.6/go.mod h1:/FALq9T/kS7b5J5qsQ+RSTUdAmGFqi0vUdVNNx8q630=
|
||||||
github.com/Azure/go-autorest/autorest v0.10.2 h1:NuSF3gXetiHyUbVdneJMEVyPUYAe5wh+aN08JYAf1tI=
|
github.com/Azure/go-autorest/autorest v0.10.2 h1:NuSF3gXetiHyUbVdneJMEVyPUYAe5wh+aN08JYAf1tI=
|
||||||
github.com/Azure/go-autorest/autorest v0.10.2/go.mod h1:/FALq9T/kS7b5J5qsQ+RSTUdAmGFqi0vUdVNNx8q630=
|
github.com/Azure/go-autorest/autorest v0.10.2/go.mod h1:/FALq9T/kS7b5J5qsQ+RSTUdAmGFqi0vUdVNNx8q630=
|
||||||
github.com/Azure/go-autorest/autorest/adal v0.5.0/go.mod h1:8Z9fGy2MpX0PvDjB1pEgQTmVqjGhiHBW7RJJEciWzS0=
|
github.com/Azure/go-autorest/autorest/adal v0.5.0/go.mod h1:8Z9fGy2MpX0PvDjB1pEgQTmVqjGhiHBW7RJJEciWzS0=
|
||||||
github.com/Azure/go-autorest/autorest/adal v0.8.0/go.mod h1:Z6vX6WXXuyieHAXwMj0S6HY6e6wcHn37qQMBQlvY3lc=
|
github.com/Azure/go-autorest/autorest/adal v0.8.0/go.mod h1:Z6vX6WXXuyieHAXwMj0S6HY6e6wcHn37qQMBQlvY3lc=
|
||||||
github.com/Azure/go-autorest/autorest/adal v0.8.2 h1:O1X4oexUxnZCaEUGsvMnr8ZGj8HI37tNezwY4npRqA0=
|
|
||||||
github.com/Azure/go-autorest/autorest/adal v0.8.2/go.mod h1:ZjhuQClTqx435SRJ2iMlOxPYt3d2C/T/7TiQCVZSn3Q=
|
github.com/Azure/go-autorest/autorest/adal v0.8.2/go.mod h1:ZjhuQClTqx435SRJ2iMlOxPYt3d2C/T/7TiQCVZSn3Q=
|
||||||
github.com/Azure/go-autorest/autorest/adal v0.9.5 h1:Y3bBUV4rTuxenJJs41HU3qmqsb+auo+a3Lz+PlJPpL0=
|
github.com/Azure/go-autorest/autorest/adal v0.9.5 h1:Y3bBUV4rTuxenJJs41HU3qmqsb+auo+a3Lz+PlJPpL0=
|
||||||
github.com/Azure/go-autorest/autorest/adal v0.9.5/go.mod h1:B7KF7jKIeC9Mct5spmyCB/A8CG/sEz1vwIRGv/bbw7A=
|
github.com/Azure/go-autorest/autorest/adal v0.9.5/go.mod h1:B7KF7jKIeC9Mct5spmyCB/A8CG/sEz1vwIRGv/bbw7A=
|
||||||
github.com/Azure/go-autorest/autorest/date v0.1.0/go.mod h1:plvfp3oPSKwf2DNjlBjWF/7vwR+cUD/ELuzDCXwHUVA=
|
github.com/Azure/go-autorest/autorest/date v0.1.0/go.mod h1:plvfp3oPSKwf2DNjlBjWF/7vwR+cUD/ELuzDCXwHUVA=
|
||||||
github.com/Azure/go-autorest/autorest/date v0.2.0 h1:yW+Zlqf26583pE43KhfnhFcdmSWlm5Ew6bxipnr/tbM=
|
|
||||||
github.com/Azure/go-autorest/autorest/date v0.2.0/go.mod h1:vcORJHLJEh643/Ioh9+vPmf1Ij9AEBM5FuBIXLmIy0g=
|
github.com/Azure/go-autorest/autorest/date v0.2.0/go.mod h1:vcORJHLJEh643/Ioh9+vPmf1Ij9AEBM5FuBIXLmIy0g=
|
||||||
github.com/Azure/go-autorest/autorest/date v0.3.0 h1:7gUk1U5M/CQbp9WoqinNzJar+8KY+LPI6wiWrP/myHw=
|
github.com/Azure/go-autorest/autorest/date v0.3.0 h1:7gUk1U5M/CQbp9WoqinNzJar+8KY+LPI6wiWrP/myHw=
|
||||||
github.com/Azure/go-autorest/autorest/date v0.3.0/go.mod h1:BI0uouVdmngYNUzGWeSYnokU+TrmwEsOqdt8Y6sso74=
|
github.com/Azure/go-autorest/autorest/date v0.3.0/go.mod h1:BI0uouVdmngYNUzGWeSYnokU+TrmwEsOqdt8Y6sso74=
|
||||||
github.com/Azure/go-autorest/autorest/mocks v0.1.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0=
|
github.com/Azure/go-autorest/autorest/mocks v0.1.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0=
|
||||||
github.com/Azure/go-autorest/autorest/mocks v0.2.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0=
|
github.com/Azure/go-autorest/autorest/mocks v0.2.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0=
|
||||||
github.com/Azure/go-autorest/autorest/mocks v0.3.0 h1:qJumjCaCudz+OcqE9/XtEPfvtOjOmKaui4EOpFI6zZc=
|
|
||||||
github.com/Azure/go-autorest/autorest/mocks v0.3.0/go.mod h1:a8FDP3DYzQ4RYfVAxAN3SVSiiO77gL2j2ronKKP0syM=
|
github.com/Azure/go-autorest/autorest/mocks v0.3.0/go.mod h1:a8FDP3DYzQ4RYfVAxAN3SVSiiO77gL2j2ronKKP0syM=
|
||||||
github.com/Azure/go-autorest/autorest/mocks v0.4.1 h1:K0laFcLE6VLTOwNgSxaGbUcLPuGXlNkbVvq4cW4nIHk=
|
github.com/Azure/go-autorest/autorest/mocks v0.4.1 h1:K0laFcLE6VLTOwNgSxaGbUcLPuGXlNkbVvq4cW4nIHk=
|
||||||
github.com/Azure/go-autorest/autorest/mocks v0.4.1/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k=
|
github.com/Azure/go-autorest/autorest/mocks v0.4.1/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k=
|
||||||
@ -60,7 +55,6 @@ github.com/Azure/go-autorest/autorest/validation v0.1.0/go.mod h1:Ha3z/SqBeaalWQ
|
|||||||
github.com/Azure/go-autorest/autorest/validation v0.2.0/go.mod h1:3EEqHnBxQGHXRYq3HT1WyXAvT7LLY3tl70hw6tQIbjI=
|
github.com/Azure/go-autorest/autorest/validation v0.2.0/go.mod h1:3EEqHnBxQGHXRYq3HT1WyXAvT7LLY3tl70hw6tQIbjI=
|
||||||
github.com/Azure/go-autorest/logger v0.1.0 h1:ruG4BSDXONFRrZZJ2GUXDiUyVpayPmb1GnWeHDdaNKY=
|
github.com/Azure/go-autorest/logger v0.1.0 h1:ruG4BSDXONFRrZZJ2GUXDiUyVpayPmb1GnWeHDdaNKY=
|
||||||
github.com/Azure/go-autorest/logger v0.1.0/go.mod h1:oExouG+K6PryycPJfVSxi/koC6LSNgds39diKLz7Vrc=
|
github.com/Azure/go-autorest/logger v0.1.0/go.mod h1:oExouG+K6PryycPJfVSxi/koC6LSNgds39diKLz7Vrc=
|
||||||
github.com/Azure/go-autorest/tracing v0.5.0 h1:TRn4WjSnkcSy5AEG3pnbtFSwNtwzjr4VYyQflFE619k=
|
|
||||||
github.com/Azure/go-autorest/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbtp2fGCgRFtBroKn4Dk=
|
github.com/Azure/go-autorest/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbtp2fGCgRFtBroKn4Dk=
|
||||||
github.com/Azure/go-autorest/tracing v0.6.0 h1:TYi4+3m5t6K48TGI9AUdb+IzbnSxvnvUMfuitfgcfuo=
|
github.com/Azure/go-autorest/tracing v0.6.0 h1:TYi4+3m5t6K48TGI9AUdb+IzbnSxvnvUMfuitfgcfuo=
|
||||||
github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU=
|
github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU=
|
||||||
@ -142,11 +136,12 @@ github.com/cpuguy83/go-md2man/v2 v2.0.0 h1:EoUDS0afbrsXAZ9YQ9jdu/mZ2sXgT1/2yyNng
|
|||||||
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
||||||
github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
|
github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
|
||||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||||
|
github.com/cyphar/filepath-securejoin v0.2.2 h1:jCwT2GTP+PY5nBz3c/YL5PAIbusElVrPujOBSCj8xRg=
|
||||||
|
github.com/cyphar/filepath-securejoin v0.2.2/go.mod h1:FpkQEhXnPnOthhzymB7CGsFk2G9VLXONKD9G7QGMM+4=
|
||||||
github.com/davecgh/go-spew v0.0.0-20151105211317-5215b55f46b2/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v0.0.0-20151105211317-5215b55f46b2/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM=
|
|
||||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
|
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
|
||||||
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
|
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
|
||||||
github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E=
|
github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E=
|
||||||
|
|||||||
50
internal/flags/safe_relative_path.go
Normal file
50
internal/flags/safe_relative_path.go
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2020 The Flux authors
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package flags
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
securejoin "github.com/cyphar/filepath-securejoin"
|
||||||
|
)
|
||||||
|
|
||||||
|
type SafeRelativePath string
|
||||||
|
|
||||||
|
func (p *SafeRelativePath) String() string {
|
||||||
|
return string(*p)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *SafeRelativePath) Set(str string) error {
|
||||||
|
// The result of secure joining on a relative base dir is a flattened relative path.
|
||||||
|
cleanP, err := securejoin.SecureJoin("./", strings.TrimSpace(str))
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("invalid relative path '%s': %w", cleanP, err)
|
||||||
|
}
|
||||||
|
// NB: required, as a secure join of "./" will result in "."
|
||||||
|
cleanP = fmt.Sprintf("./%s", strings.TrimPrefix(cleanP, "."))
|
||||||
|
*p = SafeRelativePath(cleanP)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *SafeRelativePath) Type() string {
|
||||||
|
return "safeRelativePath"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *SafeRelativePath) Description() string {
|
||||||
|
return fmt.Sprintf("secure relative path")
|
||||||
|
}
|
||||||
49
internal/flags/safe_relative_path_test.go
Normal file
49
internal/flags/safe_relative_path_test.go
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2020 The Flux authors
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package flags
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestRelativePath_Set(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
str string
|
||||||
|
expect string
|
||||||
|
expectErr bool
|
||||||
|
}{
|
||||||
|
{"relative path", "./foo", "./foo", false},
|
||||||
|
{"relative path", "foo", "./foo", false},
|
||||||
|
{"traversing relative path", "./foo/../bar", "./bar", false},
|
||||||
|
{"absolute path", "/foo", "./foo", false},
|
||||||
|
{"traversing absolute path", "/foo/../bar", "./bar", false},
|
||||||
|
{"traversing overflowing absolute path", "/foo/../../../bar", "./bar", false},
|
||||||
|
{"empty", "", "./", false},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
var p SafeRelativePath
|
||||||
|
if err := p.Set(tt.str); (err != nil) != tt.expectErr {
|
||||||
|
t.Errorf("Set() error = %v, expectErr %v", err, tt.expectErr)
|
||||||
|
}
|
||||||
|
if str := p.String(); str != tt.expect {
|
||||||
|
t.Errorf("Set() = %v, expect %v", str, tt.expect)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -24,6 +24,8 @@ import (
|
|||||||
"path"
|
"path"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
securejoin "github.com/cyphar/filepath-securejoin"
|
||||||
|
|
||||||
"github.com/fluxcd/flux2/pkg/manifestgen"
|
"github.com/fluxcd/flux2/pkg/manifestgen"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -40,7 +42,10 @@ func Generate(options Options) (*manifestgen.Manifest, error) {
|
|||||||
}
|
}
|
||||||
defer os.RemoveAll(tmpDir)
|
defer os.RemoveAll(tmpDir)
|
||||||
|
|
||||||
output := path.Join(tmpDir, options.ManifestFile)
|
output, err := securejoin.SecureJoin(tmpDir, options.ManifestFile)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
if !strings.HasPrefix(options.BaseURL, "http") {
|
if !strings.HasPrefix(options.BaseURL, "http") {
|
||||||
if err := build(options.BaseURL, output); err != nil {
|
if err := build(options.BaseURL, output); err != nil {
|
||||||
|
|||||||
@ -20,8 +20,9 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
|
||||||
|
securejoin "github.com/cyphar/filepath-securejoin"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Manifest holds the data of a multi-doc YAML
|
// Manifest holds the data of a multi-doc YAML
|
||||||
@ -36,14 +37,17 @@ type Manifest struct {
|
|||||||
// If the file does not exist, WriteFile creates it with permissions perm,
|
// If the file does not exist, WriteFile creates it with permissions perm,
|
||||||
// otherwise WriteFile overwrites the file, without changing permissions.
|
// otherwise WriteFile overwrites the file, without changing permissions.
|
||||||
func (m *Manifest) WriteFile(rootDir string) (string, error) {
|
func (m *Manifest) WriteFile(rootDir string) (string, error) {
|
||||||
if err := os.MkdirAll(path.Join(rootDir, filepath.Dir(m.Path)), os.ModePerm); err != nil {
|
output, err := securejoin.SecureJoin(rootDir, m.Path)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := os.MkdirAll(filepath.Dir(output), os.ModePerm); err != nil {
|
||||||
return "", fmt.Errorf("unable to create dir, error: %w", err)
|
return "", fmt.Errorf("unable to create dir, error: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
filePath := path.Join(rootDir, m.Path)
|
if err := ioutil.WriteFile(output, []byte(m.Content), os.ModePerm); err != nil {
|
||||||
if err := ioutil.WriteFile(filePath, []byte(m.Content), os.ModePerm); err != nil {
|
|
||||||
return "", fmt.Errorf("unable to write file, error: %w", err)
|
return "", fmt.Errorf("unable to write file, error: %w", err)
|
||||||
}
|
}
|
||||||
|
return output, nil
|
||||||
return filePath, nil
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user