Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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)
}
18 changes: 15 additions & 3 deletions cmd/dev.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@ import (
"encoding/json"
"fmt"

"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 @@ -59,9 +61,6 @@ func getMetadataRows(m *common.Metadata) [][]string {
}
metadataRows = append(metadataRows, []string{"Labels", cli.CommaSeparated(labelRows)})
}
if m.Description != "" {
metadataRows = append(metadataRows, []string{"Description", m.Description})
}
return metadataRows
}
return nil
Expand All @@ -78,6 +77,19 @@ func unMarshalMetadata(m string) *common.MetadataMutable {
return nil
}

// 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
66 changes: 30 additions & 36 deletions cmd/policy-attributes.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import (
"fmt"
"strings"

"github.com/opentdf/platform/protocol/go/policy/attributes"
"github.com/opentdf/platform/protocol/go/policy"
"github.com/opentdf/tructl/pkg/cli"
"github.com/spf13/cobra"
)
Expand Down Expand Up @@ -51,7 +51,7 @@ used to define the access controls based on subject encodings and entity entitle
}

// create attribute values
attrValues := make([]*attributes.Value, 0, len(values))
attrValues := make([]*policy.Value, 0, len(values))
valueErrors := make(map[string]error)
for _, value := range values {
v, err := h.CreateAttributeValue(attr.Id, value)
Expand All @@ -61,30 +61,28 @@ used to define the access controls based on subject encodings and entity entitle
attrValues = append(attrValues, v)
}

a := cli.GetSimpleAttribute(&attributes.Attribute{
a := cli.GetSimpleAttribute(&policy.Attribute{
Id: attr.Id,
Name: attr.Name,
Rule: attr.Rule,
Values: attrValues,
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 @@ -107,17 +105,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 @@ -146,7 +142,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 @@ -177,16 +173,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 @@ -201,10 +195,10 @@ used to define the access controls based on subject encodings and entity entitle
flagHelper := cli.NewFlagHelper(cmd)
id := flagHelper.GetRequiredString("id")

if _, err := h.UpdateAttribute(id); err != nil {
if a, err := h.UpdateAttribute(id); 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
53 changes: 26 additions & 27 deletions cmd/policy-namespaces.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,14 +46,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 @@ -77,7 +75,7 @@ or different attributes tied to each.
ns.Name,
)
}
fmt.Println(t.Render())
HandleSuccess(cmd, "", t, list)
},
}

Expand All @@ -96,13 +94,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 @@ -131,14 +127,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 @@ -155,13 +149,18 @@ or different attributes tied to each.
id := flagHelper.GetRequiredString("id")
name := flagHelper.GetRequiredString("name")

if _, err := h.UpdateNamespace(
ns, err := h.UpdateNamespace(
id,
name,
); err != nil {
)
if err != nil {
cli.ExitWithError("Could not update namespace", err)
}
fmt.Println(cli.SuccessMessage(fmt.Sprintf("Namespace id: (%s) updated. Name set to (%s).", id, name)))
t := cli.NewTabular().Rows([][]string{
{"Id", ns.Id},
{"Name", ns.Name},
}...)
HandleSuccess(cmd, id, t, ns)
},
}
)
Expand Down
Loading