Skip to content

Commit

Permalink
Merge branch 'main' into feat/subject-mappings
Browse files Browse the repository at this point in the history
  • Loading branch information
jakedoublev committed Mar 20, 2024
2 parents 267f314 + 69b7792 commit c3daeba
Show file tree
Hide file tree
Showing 16 changed files with 319 additions and 150 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ The main goals are to:

## TODO list

- [ ] Add support for `--json` persistent flag
- [ ] Add support for json input as piped input
- [ ] Add help level handler for each command
- [ ] Add support for `--verbose` persistent flag
Expand All @@ -28,13 +27,14 @@ The CLI is built using [cobra](https://cobra.dev/).

The primary function is to support CRUD operations using commands as arguments and flags as the values.

The output format (currently `styled` or `json`) is configurable in the `tructl.yaml` or via CLI flag.

#### To add a command

1. Capture the flag value and validate the values
1. Alt support JSON input as piped input
2. Run the handler which is located in `pkg/handlers` and pass the values as arguments
3. Handle any errors and return the result in a lite TUI format
1. Alt support JSON output when `--json` flag is passed

### TUI

Expand Down
46 changes: 46 additions & 0 deletions cmd/config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package cmd

import (
"fmt"

"github.com/opentdf/tructl/internal/config"
"github.com/opentdf/tructl/pkg/cli"
"github.com/spf13/cobra"
)

// configCmd is the command for managing configuration
var configCmd = &cobra.Command{
Use: "config",
Short: "Manage configuration",
Long: `
Manage configuration within 'tructl'.
Configuration is used to manage the configuration of the 'tructl' command line tool and updates the
config .yaml file in the root directory when changes have been made.
`,
}

var updateOutputFormatCmd = &cobra.Command{
Use: "output",
Short: "Define the configured output format",
Long: `
Define the configured output format for the 'tructl' command line tool. The only supported outputs at
this time are 'json' and styled CLI output, which is the default when unspecified.
`,
Run: func(cmd *cobra.Command, args []string) {
h := cli.NewHandler(cmd)
defer h.Close()

flagHelper := cli.NewFlagHelper(cmd)
format := flagHelper.GetRequiredString("format")

config.UpdateOutputFormat(format)
fmt.Println(cli.SuccessMessage(fmt.Sprintf("Output format updated to %s", format)))
},
}

func init() {
updateOutputFormatCmd.Flags().String("format", "", "'json' or 'styled' as the configured output format")
configCmd.AddCommand(updateOutputFormatCmd)
rootCmd.AddCommand(configCmd)
}
15 changes: 15 additions & 0 deletions cmd/dev.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@ import (
"fmt"
"strings"

"github.com/charmbracelet/lipgloss/table"
"github.com/opentdf/platform/protocol/go/common"
"github.com/opentdf/tructl/internal/config"
"github.com/opentdf/tructl/pkg/cli"
"github.com/spf13/cobra"
)
Expand Down Expand Up @@ -99,6 +101,19 @@ func getMetadataUpdateBehavior() common.MetadataUpdateEnum {
return common.MetadataUpdateEnum_METADATA_UPDATE_ENUM_EXTEND
}

// HandleSuccess prints a success message according to the configured format (styled table or JSON)
func HandleSuccess(command *cobra.Command, id string, t *table.Table, policyObject interface{}) {
if TructlCfg.Output.Format == config.OutputJSON || configFlagOverrides.OutputFormatJSON {
if output, err := json.MarshalIndent(policyObject, "", " "); err != nil {
cli.ExitWithError("Error marshalling policy object", err)
} else {
fmt.Println(string(output))
}
return
}
cli.PrintSuccessTable(command, id, t)
}

func init() {
rootCmd.AddCommand(devCmd)
devCmd.AddCommand(designCmd)
Expand Down
60 changes: 27 additions & 33 deletions cmd/policy-attributes.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,22 +74,20 @@ used to define the access controls based on subject encodings and entity entitle
Namespace: attr.Namespace,
})

fmt.Println(cli.SuccessMessage("Attribute created"))
fmt.Println(
cli.NewTabular().Rows([][]string{
{"Name", a.Name},
{"Rule", a.Rule},
{"Values", cli.CommaSeparated(a.Values)},
{"Namespace", a.Namespace},
}...).Render(),
)
t := cli.NewTabular().Rows([][]string{
{"Name", a.Name},
{"Rule", a.Rule},
{"Values", cli.CommaSeparated(a.Values)},
{"Namespace", a.Namespace},
}...)

if len(valueErrors) > 0 {
fmt.Println(cli.ErrorMessage("Error creating attribute values", nil))
for value, err := range valueErrors {
cli.ErrorMessage(value, err)
}
}
HandleSuccess(cmd, a.Id, t, a)
},
}

Expand All @@ -112,17 +110,15 @@ used to define the access controls based on subject encodings and entity entitle
}

a := cli.GetSimpleAttribute(attr)
fmt.Println(cli.SuccessMessage("Attribute found"))
fmt.Println(
cli.NewTabular().
Rows([][]string{
{"Id", a.Id},
{"Name", a.Name},
{"Rule", a.Rule},
{"Values", cli.CommaSeparated(a.Values)},
{"Namespace", a.Namespace},
}...).Render(),
)
t := cli.NewTabular().
Rows([][]string{
{"Id", a.Id},
{"Name", a.Name},
{"Rule", a.Rule},
{"Values", cli.CommaSeparated(a.Values)},
{"Namespace", a.Namespace},
}...)
HandleSuccess(cmd, a.Id, t, a)
},
}

Expand Down Expand Up @@ -151,7 +147,7 @@ used to define the access controls based on subject encodings and entity entitle
cli.CommaSeparated(a.Values),
)
}
fmt.Println(t.Render())
HandleSuccess(cmd, "", t, attrs)
},
}

Expand Down Expand Up @@ -182,16 +178,14 @@ used to define the access controls based on subject encodings and entity entitle
}

a := cli.GetSimpleAttribute(attr)
fmt.Println(cli.SuccessMessage("Attribute deactivated"))
fmt.Println(
cli.NewTabular().
Rows([][]string{
{"Name", a.Name},
{"Rule", a.Rule},
{"Values", cli.CommaSeparated(a.Values)},
{"Namespace", a.Namespace},
}...).Render(),
)
t := cli.NewTabular().
Rows([][]string{
{"Name", a.Name},
{"Rule", a.Rule},
{"Values", cli.CommaSeparated(a.Values)},
{"Namespace", a.Namespace},
}...)
HandleSuccess(cmd, a.Id, t, a)
},
}

Expand All @@ -207,10 +201,10 @@ used to define the access controls based on subject encodings and entity entitle
id := flagHelper.GetRequiredString("id")
labels := flagHelper.GetStringSlice("label", metadataLabels, cli.FlagHelperStringSliceOptions{Min: 0})

if _, err := h.UpdateAttribute(id, getMetadata(labels), getMetadataUpdateBehavior()); err != nil {
if a, err := h.UpdateAttribute(id, getMetadata(labels), getMetadataUpdateBehavior()); err != nil {
cli.ExitWithError("Could not update attribute", err)
} else {
fmt.Println(cli.SuccessMessage(fmt.Sprintf("Attribute id: %s updated.", id)))
HandleSuccess(cmd, id, nil, a)
}
},
}
Expand Down
54 changes: 27 additions & 27 deletions cmd/policy-namespaces.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,14 +48,12 @@ or different attributes tied to each.
cli.ExitWithError(errMsg, err)
}

fmt.Println(cli.SuccessMessage("Namespace found"))
fmt.Println(
cli.NewTabular().
Rows([][]string{
{"Id", ns.Id},
{"Name", ns.Name},
}...).Render(),
)
t := cli.NewTabular().
Rows([][]string{
{"Id", ns.Id},
{"Name", ns.Name},
}...)
HandleSuccess(cmd, ns.Id, t, ns)
},
}

Expand All @@ -79,7 +77,7 @@ or different attributes tied to each.
ns.Name,
)
}
fmt.Println(t.Render())
HandleSuccess(cmd, "", t, list)
},
}

Expand All @@ -99,13 +97,11 @@ or different attributes tied to each.
cli.ExitWithError("Could not create namespace", err)
}

fmt.Println(cli.SuccessMessage("Namespace created"))
fmt.Println(
cli.NewTabular().Rows([][]string{
{"Name", name},
{"Id", created.Id},
}...).Render(),
)
t := cli.NewTabular().Rows([][]string{
{"Name", name},
{"Id", created.Id},
}...)
HandleSuccess(cmd, created.Id, t, created)
},
}

Expand Down Expand Up @@ -134,14 +130,12 @@ or different attributes tied to each.
cli.ExitWithError(errMsg, err)
}

fmt.Println(cli.SuccessMessage("Namespace deactivated"))
fmt.Println(
cli.NewTabular().
Rows([][]string{
{"Id", ns.Id},
{"Name", ns.Name},
}...).Render(),
)
t := cli.NewTabular().
Rows([][]string{
{"Id", ns.Id},
{"Name", ns.Name},
}...)
HandleSuccess(cmd, ns.Id, t, ns)
},
}

Expand All @@ -157,14 +151,20 @@ or different attributes tied to each.
id := flagHelper.GetRequiredString("id")
labels := flagHelper.GetStringSlice("label", metadataLabels, cli.FlagHelperStringSliceOptions{Min: 0})

if _, err := h.UpdateNamespace(
ns, err := h.UpdateNamespace(
id,
getMetadata(labels),
getMetadataUpdateBehavior(),
); err != nil {
)
if err != nil {
cli.ExitWithError("Could not update namespace", err)
}
fmt.Println(cli.SuccessMessage(fmt.Sprintf("Namespace id: (%s) updated.", id)))

t := cli.NewTabular().Rows([][]string{
{"Id", ns.Id},
{"Name", ns.Name},
}...)
HandleSuccess(cmd, id, t, ns)
},
}
)
Expand Down
30 changes: 15 additions & 15 deletions cmd/policy-resource_mappings.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package cmd

import (
_ "embed"
"fmt"
"strings"

"github.com/opentdf/tructl/docs/man"
Expand Down Expand Up @@ -47,13 +46,13 @@ var (
cli.ExitWithError("Failed to create resource mapping", err)
}

fmt.Println(cli.SuccessMessage("Resource mapping created"))
fmt.Println(cli.NewTabular().Rows([][]string{
t := cli.NewTabular().Rows([][]string{
{"Id", resourceMapping.Id},
{"Attribute Value Id", resourceMapping.AttributeValue.Id},
{"Attribute Value", resourceMapping.AttributeValue.Value},
{"Terms", strings.Join(resourceMapping.Terms, ", ")},
}...).Render())
}...)
HandleSuccess(cmd, resourceMapping.Id, t, resourceMapping)
},
}

Expand All @@ -72,12 +71,13 @@ var (
cli.ExitWithError("Failed to get resource mapping", err)
}

fmt.Println(cli.NewTabular().Rows([][]string{
t := cli.NewTabular().Rows([][]string{
{"Id", resourceMapping.Id},
{"Attribute Value Id", resourceMapping.AttributeValue.Id},
{"Attribute Value", resourceMapping.AttributeValue.Value},
{"Terms", strings.Join(resourceMapping.Terms, ", ")},
}...).Render())
}...)
HandleSuccess(cmd, resourceMapping.Id, t, resourceMapping)
},
}

Expand All @@ -88,17 +88,17 @@ var (
h := cli.NewHandler(cmd)
defer h.Close()

r, err := h.ListResourceMappings()
rmList, err := h.ListResourceMappings()
if err != nil {
cli.ExitWithError("Failed to list resource mappings", err)
}

t := cli.NewTable()
t.Headers("Id", "Attribute Value Id", "Attribute Value", "Terms")
for _, resourceMapping := range r {
for _, resourceMapping := range rmList {
t.Row(resourceMapping.Id, resourceMapping.AttributeValue.Id, resourceMapping.AttributeValue.Value, strings.Join(resourceMapping.Terms, ", "))
}
fmt.Println(t.Render())
HandleSuccess(cmd, "", t, rmList)
},
}

Expand All @@ -120,13 +120,13 @@ var (
cli.ExitWithError("Failed to update resource mapping", err)
}

fmt.Println(cli.SuccessMessage("Resource mapping updated"))
fmt.Println(cli.NewTabular().Rows([][]string{
t := cli.NewTabular().Rows([][]string{
{"Id", resourceMapping.Id},
{"Attribute Value Id", resourceMapping.AttributeValue.Id},
{"Attribute Value", resourceMapping.AttributeValue.Value},
{"Terms", strings.Join(resourceMapping.Terms, ", ")},
}...).Render())
}...)
HandleSuccess(cmd, resourceMapping.Id, t, resourceMapping)
},
}

Expand All @@ -147,13 +147,13 @@ var (
cli.ExitWithError("Failed to delete resource mapping", err)
}

fmt.Println(cli.SuccessMessage("Resource mapping deleted"))
fmt.Println(cli.NewTabular().Rows([][]string{
t := cli.NewTabular().Rows([][]string{
{"Id", resourceMapping.Id},
{"Attribute Value Id", resourceMapping.AttributeValue.Id},
{"Attribute Value", resourceMapping.AttributeValue.Value},
{"Terms", strings.Join(resourceMapping.Terms, ", ")},
}...).Render())
}...)
HandleSuccess(cmd, resourceMapping.Id, t, resourceMapping)
},
}
)
Expand Down
Loading

0 comments on commit c3daeba

Please sign in to comment.