registry

package
v0.25.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 3, 2024 License: MIT Imports: 17 Imported by: 0

Documentation

Index

Constants

View Source
const (
	SyncTempDirPrefix = "granted-registry-sync"
)
View Source
const (
	// permission for user to read/write/execute.
	USER_READ_WRITE_PERM = 0700
)

Variables

View Source
var AddCommand = cli.Command{
	Name:        "add",
	Description: "Add a Profile Registry that you want to sync with aws config file",
	Usage:       "Provide git repository you want to sync with aws config file",
	Flags: []cli.Flag{
		&cli.StringFlag{Name: "name", Required: true, Usage: "A unique name for the profile registry", Aliases: []string{"n"}},
		&cli.StringFlag{Name: "url", Required: true, Usage: "The URL for the registry", Aliases: []string{"u"}},
		&cli.StringFlag{Name: "path", Usage: "For git registries: provide path if only the subfolder needs to be synced", Aliases: []string{"p"}},
		&cli.StringFlag{Name: "filename", Aliases: []string{"f"}, Usage: "For git registries:  provide filename if yml file is not granted.yml", DefaultText: "granted.yml"},
		&cli.IntFlag{Name: "priority", Usage: "The priority for the profile registry", Value: 0},
		&cli.StringFlag{Name: "ref", Hidden: true},
		&cli.BoolFlag{Name: "prefix-all-profiles", Aliases: []string{"pap"}, Usage: "Provide this flag if you want to append registry name to all profiles"},
		&cli.BoolFlag{Name: "prefix-duplicate-profiles", Aliases: []string{"pdp"}, Usage: "Provide this flag if you want to append registry name to duplicate profiles"},
		&cli.BoolFlag{Name: "write-on-sync-failure", Aliases: []string{"wosf"}, Usage: "Always overwrite AWS config, even if sync fails (DEPRECATED)"},
		&cli.StringSliceFlag{Name: "required-key", Aliases: []string{"r", "requiredKey"}, Usage: "Used to bypass the prompt or override user specific values"}},
	ArgsUsage: "--name <registry_name> --url <repository_url>",
	Action: func(c *cli.Context) error {
		ctx := c.Context

		gConf, err := grantedConfig.Load()
		if err != nil {
			return err
		}

		if c.Bool("write-on-sync-failure") {
			return errors.New("'--write-on-sync-failure' has been deprecated. Please raise an issue if this has affected your workflows: https://github.com/common-fate/granted/issues/new")
		}

		name := c.String("name")
		gitURL := c.String("url")
		pathFlag := c.String("path")
		configFileName := c.String("filename")
		ref := c.String("ref")
		prefixAllProfiles := c.Bool("prefix-all-profiles")
		prefixDuplicateProfiles := c.Bool("prefix-duplicate-profiles")
		requiredKey := c.StringSlice("required-key")
		priority := c.Int("priority")

		for _, r := range gConf.ProfileRegistry.Registries {
			if r.Name == name {
				clio.Errorf("profile registry with name '%s' already exists. Name is required to be unique. Try adding with different name.\n", name)

				return nil
			}
		}

		registryConfig := grantedConfig.Registry{
			Name:                    name,
			URL:                     gitURL,
			Path:                    pathFlag,
			Filename:                configFileName,
			Ref:                     ref,
			Priority:                priority,
			PrefixDuplicateProfiles: prefixDuplicateProfiles,
			PrefixAllProfiles:       prefixAllProfiles,
		}

		registry, err := gitregistry.New(gitregistry.Opts{
			Name:         name,
			URL:          gitURL,
			Path:         pathFlag,
			Filename:     configFileName,
			RequiredKeys: requiredKey,
			Interactive:  true,
		})

		if err != nil {
			return err
		}

		src, err := registry.AWSProfiles(ctx)
		if err != nil {
			return err
		}

		dst, filepath, err := loadAWSConfigFile()
		if err != nil {
			return err
		}

		m := awsmerge.Merger{}

		merged, err := m.WithRegistry(src, dst, awsmerge.RegistryOpts{
			Name:                    name,
			PrefixAllProfiles:       prefixAllProfiles,
			PrefixDuplicateProfiles: prefixDuplicateProfiles,
		})
		var dpe awsmerge.DuplicateProfileError
		if errors.As(err, &dpe) {
			clio.Warnf(err.Error())

			const (
				DUPLICATE = "Add registry name as prefix to all duplicate profiles for this registry"
				ABORT     = "Abort, I will manually fix this"
			)

			options := []string{DUPLICATE, ABORT}

			in := survey.Select{Message: "Please select which option would you like to choose to resolve: ", Options: options}
			var selected string
			err = testable.AskOne(&in, &selected)
			if err != nil {
				return err
			}

			if selected == ABORT {
				return fmt.Errorf("aborting sync for registry %s", name)
			}

			registryConfig.PrefixDuplicateProfiles = true

			merged, err = m.WithRegistry(src, dst, awsmerge.RegistryOpts{
				Name:                    name,
				PrefixAllProfiles:       prefixAllProfiles,
				PrefixDuplicateProfiles: true,
			})
			if err != nil {
				return fmt.Errorf("error after trying to merge profiles again: %w", err)
			}
		}

		gConf.ProfileRegistry.Registries = append(gConf.ProfileRegistry.Registries, registryConfig)
		err = gConf.Save()
		if err != nil {
			return err
		}

		err = merged.SaveTo(filepath)
		if err != nil {
			return err
		}

		return nil
	},
}
View Source
var MigrateCommand = cli.Command{
	Name:        "migrate",
	Description: "Migrate Profile Registry Configuration",
	Usage:       "Migrate Profile Registry Configuration",

	Action: func(c *cli.Context) error {
		gConf, err := grantedConfig.Load()
		if err != nil {
			clio.Debug(err.Error())
		}

		if len(gConf.ProfileRegistryURLS) > 0 {
			var registries []grantedConfig.Registry
			for i, u := range gConf.ProfileRegistryURLS {
				var msg survey.Input
				if i > 0 {
					msg = survey.Input{Message: fmt.Sprintf("Enter a registry name for %s", u), Default: fmt.Sprintf("granted-registry-%d", i)}
				} else {
					msg = survey.Input{Message: fmt.Sprintf("Enter a registry name for %s", u), Default: "granted-registry"}
				}

				var selected string
				err := testable.AskOne(&msg, &selected)
				if err != nil {
					return err
				}

				registries = append(registries, grantedConfig.Registry{
					Name: selected,
					URL:  u,
				})

			}

			gConf.ProfileRegistry.Registries = registries
			gConf.ProfileRegistryURLS = nil

			err = gConf.Save()
			if err != nil {
				clio.Debug(err.Error())
				return err
			}

			clio.Success("Successfully migrated your configuration.")

			return nil
		}

		clio.Infof("Your Profile Registry already has the latest configuration. No action required.")

		return nil
	},
}

Profile Registry data structure has been updated to accomodate different registry level options. If any user is using the previous configuration then prompt user to update the registry values.

View Source
var ProfileRegistryCommand = cli.Command{
	Name:        "registry",
	Usage:       "Manage Profile Registries",
	Description: "Profile Registries allow you to easily share AWS profile configuration in a team.",
	Subcommands: []*cli.Command{&AddCommand, &SyncCommand, &RemoveCommand, &MigrateCommand, &SetupCommand},
	Action: func(c *cli.Context) error {
		registries, err := GetProfileRegistries(true)
		if err != nil {
			return err
		}

		if len(registries) == 0 {
			clio.Warn("You haven't connected any Profile Registries yet.")
			clio.Info("Connect to a Profile Registry by running 'granted registry add -n <registry_name> -u <your_repo>'")
			return nil
		}

		clio.Info("Granted is currently synced with following registries:")
		for i, r := range registries {
			clio.Logf("\t %d: %s with name '%s'", (i + 1), r.Config.URL, r.Config.Name)
		}
		clio.NewLine()

		clio.Info("To add new registry use 'granted registry add <your_repo>'")
		clio.Info("To remove a registry use 'granted registry remove' and select from the options")
		clio.Info("To sync a registry use 'granted registry sync'")

		return nil
	},
}
View Source
var RemoveCommand = cli.Command{
	Name:        "remove",
	Description: "Unsubscribe from a Profile Registry",
	Usage:       "Unsubscribe from a Profile Registry",

	Action: func(c *cli.Context) error {
		gConf, err := grantedConfig.Load()
		if err != nil {
			return err
		}

		if len(gConf.ProfileRegistry.Registries) == 0 {
			clio.Error("There are no profile registries configured currently.\n Please use 'granted registry add <https://github.com/your-org/your-registry.git>' to add a new registry")
			return nil
		}

		registriesWithNames := []string{}

		for _, r := range gConf.ProfileRegistry.Registries {
			registriesWithNames = append(registriesWithNames, r.Name)
		}

		in := survey.Select{Message: "Please select the git repository you would like to unsubscribe:", Options: registriesWithNames}
		var out string
		err = testable.AskOne(&in, &out)
		if err != nil {
			return err
		}

		var selectedRegistry grantedConfig.Registry

		for _, r := range gConf.ProfileRegistry.Registries {
			if r.Name == out {
				selectedRegistry = r
			}
		}

		reg, err := gitregistry.New(gitregistry.Opts{
			Name:     selectedRegistry.Name,
			URL:      selectedRegistry.URL,
			Path:     selectedRegistry.Path,
			Filename: selectedRegistry.Filename,
		})
		if err != nil {
			return err
		}

		m := awsmerge.Merger{}

		configFile, awsConfigPath, err := loadAWSConfigFile()
		if err != nil {
			return err
		}

		m.RemoveRegistry(configFile, selectedRegistry.Name)

		err = configFile.SaveTo(awsConfigPath)
		if err != nil {
			return err
		}

		err = reg.Delete()
		if err != nil {
			return err
		}

		err = remove(gConf, out)
		if err != nil {
			return err
		}

		err = gConf.Save()
		if err != nil {
			return err
		}

		clio.Successf("Successfully unsubscribed from %s", out)

		return nil
	},
}
View Source
var SetupCommand = cli.Command{
	Name:        "setup",
	Usage:       "Setup a Profile Registry repository",
	Description: "Setup a granted registry repository",
	Subcommands: []*cli.Command{},
	Flags:       []cli.Flag{&cli.PathFlag{Name: "dir", Aliases: []string{"d"}, Usage: "Directory to setup the Profile Registry", Value: "granted-registry"}},
	Action: func(c *cli.Context) error {
		dir := c.Path("dir")

		err := ensureConfigDoesntExist(dir)
		if err != nil {
			return err
		}

		err = os.Mkdir(dir, 0755)
		if err != nil {
			return err
		}

		configFile, _, err := loadAWSConfigFile()
		if err != nil {
			return err
		}

		var confirm bool
		s := &survey.Confirm{
			Message: "Are you sure you want to copy all of the profiles from your AWS config file?",
			Default: true,
		}
		err = survey.AskOne(s, &confirm)
		if err != nil {
			return err
		}
		if !confirm {
			clio.Info("Cancelled registry setup")
			return nil
		}

		err = configFile.SaveTo(path.Join(dir, "config"))
		if err != nil {
			return err
		}

		f, err := os.Create(path.Join(dir, "granted.yml"))
		if err != nil {
			return err
		}
		defer f.Close()

		err = git.Init(dir)
		if err != nil {
			return err
		}

		_, err = f.WriteString(`awsConfig:
    - ./config`)
		if err != nil {
			return err
		}
		clio.Infof("Successfully created valid profile registry 'granted-registry' in %s.", dir)
		clio.Info("Now push this repository to remote origin so that your team-members can sync to it.")
		return nil
	},
}
View Source
var SyncCommand = cli.Command{
	Name:        "sync",
	Usage:       "Pull the latest change from remote origin and sync aws profiles in aws config files",
	Description: "Pull the latest change from remote origin and sync aws profiles in aws config files",
	Action: func(c *cli.Context) error {
		if err := SyncProfileRegistries(c.Context, true); err != nil {
			return err
		}

		return nil
	},
}

Functions

func GetProfileRegistries added in v0.6.0

func GetProfileRegistries(interactive bool) ([]loadedRegistry, error)

func IsOutdatedConfig added in v0.6.0

func IsOutdatedConfig() bool

func SyncProfileRegistries

func SyncProfileRegistries(ctx context.Context, interactive bool) error

Wrapper around sync func. Check if profile registry is configured, pull the latest changes and call sync func. promptUserIfProfileDuplication if true will automatically prefix the duplicate profiles and won't prompt users this is useful when new registry with higher priority is added and there is duplication with lower priority registry.

Types

type Registry

type Registry interface {
	AWSProfiles(ctx context.Context) (*ini.File, error)
}

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL