Skip to content

Commit

Permalink
keybase integration test
Browse files Browse the repository at this point in the history
  • Loading branch information
janpreet committed Aug 6, 2024
1 parent 206fb86 commit b069b94
Show file tree
Hide file tree
Showing 6 changed files with 515 additions and 42 deletions.
47 changes: 47 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ Kado is a modular configuration management tool designed to streamline and autom
- [Terraform Bead](#terraform-bead)
- [OPA Bead](#opa-bead)
- [Terragrunt Bead](#terragrunt-bead)
- [Keybase Integration](#keybase-integration)
- [Usage](#usage)
- [Commands](#commands)
- [Getting Started](#getting-started)
Expand Down Expand Up @@ -183,6 +184,52 @@ bead "terragrunt" {
}
```

## Keybase Integration

Kado integrates with Keybase to provide secure note storage and referencing within your infrastructure configurations. This feature allows you to store sensitive information securely and reference it in your bead definitions.

### Keybase Commands

- `kado keybase link`: Links your Keybase account with Kado.
- `kado keybase note create <note_name>`: Creates a new encrypted note in Keybase.
- `kado keybase note list`: Lists all stored notes.
- `kado keybase note view <note_name>`: Displays the content of a specific note.
- `kado keybase note share <note_name> <keybase_username>`: Shares a note with another Keybase user.
- `kado keybase note create-with-tags <note_name> <tag1,tag2,...>`: Creates a new note with tags.
- `kado keybase note search-by-tag <tag>`: Searches for notes with a specific tag.

### Note Referencing in Bead Definitions

You can reference Keybase notes in your bead definitions using the following syntax:

```hcl
bead "terraform" {
source = "[email protected]:janpreet/proxmox_terraform.git"
enabled = true
relay = opa
relay_field = "[email protected]:janpreet/proxmox_terraform.git,path=terraform/policies/proxmox.rego,input=terraform/plan.json,package=data.terraform.allow"
api_key = "{{keybase:note:proxmox_api_key}}"
secret_token = "{{keybase:note:secret_token}}"
}
```

In above example, `{{keybase:note:proxmox_api_key}}` and `{{keybase:note:secret_token}}` will be replaced with the content of the corresponding Keybase notes during Kado execution.

### Benefits of Keybase Integration

- **Enhanced Security**: Store sensitive information like API keys and tokens securely in Keybase.
- **Version Control**: Keybase notes are version-controlled, allowing you to track changes to sensitive information.
- **Easy Sharing**: Securely share notes with team members using Keybase's encryption.
- **Tagging System**: Organize your notes with tags for easy searching and categorization.

### Getting Started with Keybase Integration

1. Ensure you have Keybase installed and configured on your system.
2. Run `kado keybase link` to link your Keybase account with Kado.
3. Create notes for sensitive information: `kado keybase note create <note_name>`
4. Use note references in your bead definitions as shown in the example above.


## Usage

### Commands
Expand Down
98 changes: 59 additions & 39 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -135,51 +135,42 @@ func convertTemplatePaths(paths []interface{}) []string {

func main() {
var yamlFilePath string
if len(os.Args) > 1 && strings.HasSuffix(os.Args[1], ".yaml") {
yamlFilePath = os.Args[1]
} else {
yamlFilePath = "cluster.yaml"
}

if len(os.Args) > 1 && os.Args[1] == "version" {
fmt.Println("Version:", config.Version)
return
}
if len(os.Args) > 1 {
switch os.Args[1] {
case "version":
fmt.Println("Version:", config.Version)
return

if len(os.Args) > 1 && os.Args[1] == "config" {
kdFiles, err := render.GetKDFiles(".")
if err != nil {
log.Fatalf("Failed to get KD files: %v", err)
}
case "config":
handleConfigCommand()
return

var beads []bead.Bead
for _, kdFile := range kdFiles {
bs, err := config.LoadBeadsConfig(kdFile)
if err != nil {
log.Fatalf("Failed to load beads config from %s: %v", kdFile, err)
}
beads = append(beads, bs...)
}
case "fmt":
handleFormatCommand()
return

display.DisplayBeadConfig(beads)
return
}
case "ai":
engine.RunAI()
return

if len(os.Args) > 1 && os.Args[1] == "fmt" {
dir := "."
if len(os.Args) > 2 {
dir = os.Args[2]
}
err := engine.FormatKDFilesInDir(dir)
if err != nil {
log.Fatalf("Error formatting .kd files: %v", err)
}
return
}
case "keybase":
if len(os.Args) < 3 {
fmt.Println("Usage: kado keybase [debug] <command>")
return
}
helper.HandleKeybaseCommand(os.Args[2:])
return

if len(os.Args) > 1 && os.Args[1] == "ai" {
engine.RunAI()
return
default:
if strings.HasSuffix(os.Args[1], ".yaml") {
yamlFilePath = os.Args[1]
} else {
yamlFilePath = "cluster.yaml"
}
}
} else {
yamlFilePath = "cluster.yaml"
}

fmt.Println("Starting processing-")
Expand Down Expand Up @@ -285,3 +276,32 @@ func main() {
}

}

func handleConfigCommand() {
kdFiles, err := render.GetKDFiles(".")
if err != nil {
log.Fatalf("Failed to get KD files: %v", err)
}

var beads []bead.Bead
for _, kdFile := range kdFiles {
bs, err := config.LoadBeadsConfig(kdFile)
if err != nil {
log.Fatalf("Failed to load beads config from %s: %v", kdFile, err)
}
beads = append(beads, bs...)
}

display.DisplayBeadConfig(beads)
}

func handleFormatCommand() {
dir := "."
if len(os.Args) > 2 {
dir = os.Args[2]
}
err := engine.FormatKDFilesInDir(dir)
if err != nil {
log.Fatalf("Error formatting .kd files: %v", err)
}
}
147 changes: 147 additions & 0 deletions packages/helper/helper.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,11 @@ import (
"fmt"
"os"

"bufio"
"log"
"strings"
"github.com/janpreet/kado/packages/config"
"github.com/janpreet/kado/packages/keybase"
)

func SetupLandingZone() error {
Expand All @@ -31,3 +35,146 @@ func FileExists(path string) bool {
_, err := os.Stat(path)
return err == nil
}

func HandleKeybaseCommand(args []string) {
if len(args) == 0 {
fmt.Println("Usage: kado keybase [debug] <command>")
fmt.Println("Available commands: link, note")
return
}


debugIndex := -1
for i, arg := range args {
if arg == "debug" {
debugIndex = i
break
}
}

if debugIndex != -1 {
keybase.Debug = true

args = append(args[:debugIndex], args[debugIndex+1:]...)
}

switch args[0] {
case "link":
err := keybase.LinkKeybase()
if err != nil {
log.Fatalf("Failed to link Keybase account: %v", err)
}
fmt.Println("Keybase account linked successfully")
case "note":
if len(args) < 2 {
fmt.Println("Usage: kado keybase note <create|list|view|share>")
return
}
HandleNoteCommand(args[1:])
default:
fmt.Printf("Unknown Keybase command: %s\n", args[0])
fmt.Println("Available commands: link, note")
}
}

func HandleNoteCommand(args []string) {
switch args[0] {
case "create":
if len(args) < 2 {
fmt.Println("Usage: kado keybase note create <note_name>")
return
}
noteName := args[1]
fmt.Println("Enter note content (press Ctrl+D when finished):")
scanner := bufio.NewScanner(os.Stdin)
var content strings.Builder
for scanner.Scan() {
content.WriteString(scanner.Text() + "\n")
}
err := keybase.CreateNote(noteName, content.String())
if err != nil {
log.Fatalf("Failed to create note: %v", err)
}
fmt.Println("Note created successfully")

case "list":
notes, err := keybase.ListNotes()
if err != nil {
log.Fatalf("Failed to list notes: %v", err)
}
if len(notes) == 0 {
fmt.Println("No notes found")
} else {
fmt.Println("Stored notes:")
for _, note := range notes {
fmt.Println("-", note)
}
}

case "view":
if len(args) < 2 {
fmt.Println("Usage: kado keybase note view <note_name>")
return
}
noteName := args[1]
content, err := keybase.ViewNote(noteName)
if err != nil {
log.Fatalf("Failed to view note: %v", err)
}
fmt.Printf("Content of note '%s':\n%s", noteName, content)

case "share":
if len(args) < 3 {
fmt.Println("Usage: kado keybase note share <note_name> <keybase_username>")
return
}
noteName := args[1]
recipient := args[2]
err := keybase.ShareNote(noteName, recipient)
if err != nil {
log.Fatalf("Failed to share note: %v", err)
}
fmt.Printf("Note '%s' shared with %s successfully\n", noteName, recipient)

case "create-with-tags":
if len(args) < 3 {
fmt.Println("Usage: kado keybase note create-with-tags <note_name> <tag1,tag2,...>")
return
}
noteName := args[1]
tags := strings.Split(args[2], ",")
fmt.Println("Enter note content (press Ctrl+D when finished):")
content := readMultiLineInput()
err := keybase.CreateNoteWithTags(noteName, keybase.Note{Content: content, Tags: tags})
if err != nil {
log.Fatalf("Failed to create note with tags: %v", err)
}
fmt.Println("Note created successfully with tags")
case "search-by-tag":
if len(args) < 2 {
fmt.Println("Usage: kado keybase note search-by-tag <tag>")
return
}
tag := args[1]
notes, err := keybase.SearchNotesByTag(tag)
if err != nil {
log.Fatalf("Failed to search notes by tag: %v", err)
}
fmt.Printf("Notes with tag '%s':\n", tag)
for _, note := range notes {
fmt.Printf(" - %s\n", note)
}

default:
fmt.Printf("Unknown note command: %s\n", args[0])
}
}

func readMultiLineInput() string {
var content strings.Builder
scanner := bufio.NewScanner(os.Stdin)
for scanner.Scan() {
content.WriteString(scanner.Text() + "\n")
}
return content.String()
}
22 changes: 22 additions & 0 deletions packages/helper/note_resolver.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package helper

import (
"regexp"
"strings"
"fmt"
"github.com/janpreet/kado/packages/keybase"
)

var noteReferenceRegex = regexp.MustCompile(`{{keybase:note:([^}]+)}}`)

func resolveNoteReferences(input string) (string, error) {
return noteReferenceRegex.ReplaceAllStringFunc(input, func(match string) string {
noteName := strings.TrimPrefix(strings.TrimSuffix(match, "}}"), "{{keybase:note:")
content, err := keybase.ViewNote(noteName)
if err != nil {

return fmt.Sprintf("ERROR: Could not resolve note %s", noteName)
}
return strings.TrimSpace(content)
}), nil
}
4 changes: 1 addition & 3 deletions packages/helper/processer.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
// File: packages/helper/processor.go

package helper

import (
Expand Down Expand Up @@ -100,7 +98,7 @@ func ProcessTerragruntBead(b bead.Bead, yamlData map[string]interface{}, applyPl
return nil
}

// Helper functions


func convertTemplatePaths(paths []interface{}) []string {
var result []string
Expand Down
Loading

0 comments on commit b069b94

Please sign in to comment.