Skip to content

Commit

Permalink
Release v0.5.6 (#31)
Browse files Browse the repository at this point in the history
* version bump

* add codium AI pr agent

* update codium AI pr agent

* DUPLO-13650 improve format of tenant missing message

* DUPLO-13650 elide err when nil in fatal messages

* Update CHANGELOG.md

* DUPLO docs: add Homebrew installation section

* Update CHANGELOG.md

* DUPLO-26089: use a predetermined localPort (#29)

* Allowing to choose port in interactive auth

* Fixing port usage

---------

Co-authored-by: notofir <[email protected]>

* DUPLO-26089 Update versions in workflows

* DUPLO-26089 update go.mod to 1.23

* DUPLO-26089 fix a few lint issues

* DUPLO-26089 fix two more lint issues

---------

Co-authored-by: duplo-bot <[email protected]>
Co-authored-by: Joe Khoobyar <[email protected]>
Co-authored-by: David Wolfe <[email protected]>
Co-authored-by: codiumai-pr-agent-pro[bot] <151058649+codiumai-pr-agent-pro[bot]@users.noreply.github.com>
Co-authored-by: Joe Khoobyar <[email protected]>
Co-authored-by: Matheus Bafutto <[email protected]>
Co-authored-by: Zafar Abbas <[email protected]>
Co-authored-by: notofir <[email protected]>
Co-authored-by: sp1676 <[email protected]>
  • Loading branch information
10 people authored Nov 8, 2024
1 parent 2bfae75 commit 08dd6f4
Show file tree
Hide file tree
Showing 16 changed files with 90 additions and 41 deletions.
6 changes: 3 additions & 3 deletions .github/workflows/dev-check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,10 @@ jobs:
name: Set up Go
uses: actions/setup-go@v5
with:
go-version: 1.21
go-version: 1.23
-
name: Run linting
uses: golangci/golangci-lint-action@v3
uses: golangci/golangci-lint-action@v6
with:
only-new-issues: true # Only show new issues for pull requests.
format:
Expand All @@ -34,7 +34,7 @@ jobs:
name: Set up Go
uses: actions/setup-go@v5
with:
go-version: 1.21
go-version: 1.23
-
name: Run formatting
run: gofmt -s -w duplocloud cmd/duplo-aws-credential-process
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/dev-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ jobs:
name: Set up Go
uses: actions/setup-go@v5
with:
go-version: 1.21
go-version: 1.23
-
name: Run tests
run: make test
2 changes: 1 addition & 1 deletion .github/workflows/release-publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ jobs:
name: Set up Go
uses: actions/setup-go@v5
with:
go-version: 1.21
go-version: 1.23
-
name: Run tests
run: make test
Expand Down
23 changes: 23 additions & 0 deletions .pr_agent.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# See: https://github.com/Codium-ai/pr-agent/blob/main/Usage.md#working-with-github-app
# See: https://github.com/Codium-ai/pr-agent/blob/main/pr_agent/settings/configuration.toml

[pr_reviewer]
enable_review_labels_effort = true

[pr_description]
add_original_user_description = true
keep_original_user_title = true

[github_app]
handle_pr_actions = ['opened', 'reopened', 'ready_for_review', 'review_requested']
pr_commands = [
"/describe",
"/review",
"/update_changelog --pr_update_changelog.push_changelog_changes=true"
]
handle_push_trigger = true
push_commands = [
"/describe",
"/review -i --pr_reviewer.remove_previous_review_comment=true",
"/update_changelog"
]
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
## 2024-02-14

### Added
- Introduced a new section in the README for Homebrew installation, enhancing the accessibility of the tool for macOS users.

## 2024-01-24

### Fixed
- Improved error message format when a tenant is missing or not allowed.
- Prevented appending a nil error object to fatal error messages.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
VERSION=0.5.5
VERSION=0.5.6

default: all

Expand Down
10 changes: 10 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,18 @@ Command-line tools for JIT Duplo, AWS and Kubernetes access

## Installation

### From release zip files

See the *Releases* section of this repository.

- Download a release artifact that matches your system's architecture.
- Unzip the artifact.
- Install the binaries somewhere in your `PATH`, such as the `/usr/local/bin` directory.

### With Homebrew

run `brew install duplocloud/tap/duplo-jit` from your terminal

## Usage

### duplo-jit aws
Expand Down Expand Up @@ -47,6 +53,8 @@ Usage of duplo-jit:
Duplo API base URL
-interactive
Allow getting Duplo credentials via an interactive browser session
-port
Allow choosing a port for the interactive browser session. Default is random
-no-cache
Disable caching (not recommended)
-tenant string
Expand All @@ -67,6 +75,8 @@ Usage of duplo-jit:
Duplo API base URL
-interactive
Allow getting Duplo credentials via an interactive browser session
-port
Allow choosing a port for the interactive browser session. Default is random
-no-cache
Disable caching (not recommended)
-token string
Expand Down
11 changes: 6 additions & 5 deletions cmd/duplo-aws-credential-process/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import (
"github.com/duplocloud/duplo-jit/internal"
)

func mustDuploClient(host, token string, interactive, admin bool) *duplocloud.Client {
func mustDuploClient(host, token string, interactive, admin bool, port int) *duplocloud.Client {
otp := ""

// Possibly get a token from an interactive process.
Expand All @@ -21,7 +21,7 @@ func mustDuploClient(host, token string, interactive, admin bool) *duplocloud.Cl
log.Fatalf("%s: --token not specified and --interactive mode is disabled", os.Args[0])
}

tokenResult := internal.MustTokenInteractive(host, admin, "duplo-aws-credential-process")
tokenResult := internal.MustTokenInteractive(host, admin, "duplo-aws-credential-process", port)
token = tokenResult.Token
otp = tokenResult.OTP
}
Expand Down Expand Up @@ -50,6 +50,7 @@ func main() {
noCache := flag.Bool("no-cache", false, "Disable caching (not recommended)")
interactive := flag.Bool("interactive", false, "Allow getting Duplo credentials via an interactive browser session")
showVersion := flag.Bool("version", false, "Output version information and exit")
port := flag.Int("port", 0, "Port to use for the local web server")
flag.Parse()

// Output version information
Expand Down Expand Up @@ -92,7 +93,7 @@ func main() {

// Otherwise, get the credentials from Duplo.
if creds == nil {
client := mustDuploClient(*host, *token, *interactive, true)
client := mustDuploClient(*host, *token, *interactive, true, *port)
result, err := client.AdminGetJitAwsCredentials()
internal.DieIf(err, "failed to get credentials")
creds = internal.ConvertAwsCreds(result)
Expand All @@ -108,7 +109,7 @@ func main() {

// Otherwise, get the credentials from Duplo.
if creds == nil {
client := mustDuploClient(*host, *token, *interactive, true)
client := mustDuploClient(*host, *token, *interactive, true, *port)
result, err := client.AdminAwsGetJitAccess("duplo-ops")
internal.DieIf(err, "failed to get credentials")
creds = internal.ConvertAwsCreds(result)
Expand All @@ -129,7 +130,7 @@ func main() {

// Otherwise, get the credentials from Duplo.
if creds == nil {
client := mustDuploClient(*host, *token, *interactive, false)
client := mustDuploClient(*host, *token, *interactive, false, *port)

// If it doesn't look like a UUID, get the tenant ID from the name.
if len(*tenantID) < 32 {
Expand Down
23 changes: 12 additions & 11 deletions cmd/duplo-jit/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ func main() {
debug := flag.Bool("debug", false, "Turn on verbose (debugging) output")
noCache := flag.Bool("no-cache", false, "Disable caching (not recommended)")
interactive := flag.Bool("interactive", false, "Allow getting Duplo credentials via an interactive browser session")
port := flag.Int("port", 0, "Port to use for the local web server")
showVersion := flag.Bool("version", false, "Output version information and exit")
admin = new(bool)
duploOps = new(bool)
Expand Down Expand Up @@ -105,7 +106,7 @@ func main() {

// Otherwise, get the credentials from Duplo.
if creds == nil {
client, _ := internal.MustDuploClient(*host, *token, *interactive, true)
client, _ := internal.MustDuploClient(*host, *token, *interactive, true, *port)
result, err := client.AdminGetJitAwsCredentials()
internal.DieIf(err, "failed to get credentials")
creds = internal.ConvertAwsCreds(result)
Expand All @@ -121,7 +122,7 @@ func main() {

// Otherwise, get the credentials from Duplo.
if creds == nil {
client, _ := internal.MustDuploClient(*host, *token, *interactive, true)
client, _ := internal.MustDuploClient(*host, *token, *interactive, true, *port)
result, err := client.AdminAwsGetJitAccess("duplo-ops")
internal.DieIf(err, "failed to get credentials")
creds = internal.ConvertAwsCreds(result)
Expand All @@ -136,8 +137,8 @@ func main() {

// Identify the tenant name to use for the cache key.
var tenantName string
client, _ := internal.MustDuploClient(*host, *token, *interactive, false)
*tenantID, tenantName = GetTenantIdAndName(*tenantID, client)
client, _ := internal.MustDuploClient(*host, *token, *interactive, false, *port)
*tenantID, tenantName = getTenantIDAndName(*tenantID, client)

// Build the cache key.
cacheKey = strings.Join([]string{strings.TrimPrefix(*host, "https://"), "tenant", tenantName}, ",")
Expand All @@ -158,7 +159,7 @@ func main() {
internal.OutputAwsCreds(creds, cacheKey)

case "duplo":
_, creds := internal.MustDuploClient(*host, *token, *interactive, true)
_, creds := internal.MustDuploClient(*host, *token, *interactive, true, *port)
internal.OutputDuploCreds(creds)

case "k8s":
Expand All @@ -174,7 +175,7 @@ func main() {

// Otherwise, get the credentials from Duplo.
if creds == nil {
client, _ := internal.MustDuploClient(*host, *token, *interactive, true)
client, _ := internal.MustDuploClient(*host, *token, *interactive, true, *port)
result, err := client.AdminGetK8sJitAccess(*planID)
internal.DieIf(err, "failed to get credentials")
creds = internal.ConvertK8sCreds(result)
Expand All @@ -189,8 +190,8 @@ func main() {

// Identify the tenant name to use for the cache key.
var tenantName string
client, _ := internal.MustDuploClient(*host, *token, *interactive, false)
*tenantID, tenantName = GetTenantIdAndName(*tenantID, client)
client, _ := internal.MustDuploClient(*host, *token, *interactive, false, *port)
*tenantID, tenantName = getTenantIDAndName(*tenantID, client)

// Build the cache key.
cacheKey = strings.Join([]string{strings.TrimPrefix(*host, "https://"), "tenant", tenantName}, ",")
Expand All @@ -214,7 +215,7 @@ func main() {
}
}

func GetTenantIdAndName(tenantIDorName string, client *duplocloud.Client) (string, string) {
func getTenantIDAndName(tenantIDorName string, client *duplocloud.Client) (string, string) {
var tenantID string
var tenantName string

Expand All @@ -224,7 +225,7 @@ func GetTenantIdAndName(tenantIDorName string, client *duplocloud.Client) (strin
tenantName = tenantIDorName
tenant, err := client.GetTenantByNameForUser(tenantName)
if tenant == nil || err != nil {
internal.Fatal(fmt.Sprintf("%s: tenant missing or not allowed", tenantName), err)
internal.Fatal(fmt.Sprintf("tenant '%s' missing or not allowed", tenantName), err)
} else {
tenantID = tenant.TenantID
}
Expand All @@ -234,7 +235,7 @@ func GetTenantIdAndName(tenantIDorName string, client *duplocloud.Client) (strin
tenantID = tenantIDorName
tenant, err := client.GetTenantForUser(tenantIDorName)
if tenant == nil || err != nil {
internal.Fatal(fmt.Sprintf("%s: tenant missing or not allowed", tenantID), err)
internal.Fatal(fmt.Sprintf("tenant '%s' missing or not allowed", tenantID), err)
} else {
tenantName = tenant.AccountName
}
Expand Down
11 changes: 6 additions & 5 deletions duplocloud/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -100,12 +100,12 @@ func (c *Client) AdminGetK8sJitAccess(plan string) (*DuploPlanK8ClusterConfig, C
return &creds, nil
}

// AdminGetJITAwsCredentials retrieves just-in-time admin AWS credentials via the Duplo API.
// AdminGetJitAwsCredentials retrieves just-in-time admin AWS credentials via the Duplo API.
func (c *Client) AdminGetJitAwsCredentials() (*AwsJitCredentials, ClientError) {
return c.AdminAwsGetJitAccess("admin")
}

// TenantGetJITAwsCredentials retrieves just-in-time AWS credentials for a tenant via the Duplo API.
// TenantGetJitAwsCredentials retrieves just-in-time AWS credentials for a tenant via the Duplo API.
func (c *Client) TenantGetJitAwsCredentials(tenantID string) (*AwsJitCredentials, ClientError) {
creds := AwsJitCredentials{}
err := c.getAPI(
Expand Down Expand Up @@ -143,11 +143,12 @@ func (c *Client) ListTenantsForUser() (*[]UserTenant, ClientError) {
return &list, nil
}

func (c *Client) GetTenantFeatures(tenantId string) (*DuploTenantFeatures, ClientError) {
// GetTenantFeatures retrieves a tenant's current configuration via the Duplo API.
func (c *Client) GetTenantFeatures(tenantID string) (*DuploTenantFeatures, ClientError) {
features := DuploTenantFeatures{}
err := c.getAPI(
fmt.Sprintf("GetTenantFeatures(%s)", tenantId),
fmt.Sprintf("v3/features/tenant/%s", tenantId),
fmt.Sprintf("GetTenantFeatures(%s)", tenantID),
fmt.Sprintf("v3/features/tenant/%s", tenantID),
&features,
)
if err != nil {
Expand Down
4 changes: 2 additions & 2 deletions duplocloud/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import (
"time"
)

// Represents a connection to the Duplo API
// Client represents a connection to the Duplo API
type Client struct {
HTTPClient *http.Client
HostURL string
Expand Down Expand Up @@ -66,7 +66,7 @@ func (e clientError) Response() map[string]interface{} {
return e.response
}

// Represents an error from an API call.
// ClientError represents an error from an API call.
type ClientError interface {
Error() string
Status() int
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
module github.com/duplocloud/duplo-jit

go 1.21
go 1.23

require (
github.com/aws/aws-sdk-go-v2 v1.23.5
Expand Down
8 changes: 4 additions & 4 deletions internal/cache.go
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ func CacheGetAwsConfigOutput(cacheKey string) (creds *AwsConfigOutput) {

// Check credentials for expiry.
if creds != nil {
five_minutes_from_now := time.Now().UTC().Add(5 * time.Minute)
fiveMinutesFromNow := time.Now().UTC().Add(5 * time.Minute)
expiration, err := time.Parse(time.RFC3339, creds.Expiration)

// Invalid expiration?
Expand All @@ -107,7 +107,7 @@ func CacheGetAwsConfigOutput(cacheKey string) (creds *AwsConfigOutput) {
creds = nil

// Expires in five minutes or less?
} else if five_minutes_from_now.After(expiration) {
} else if fiveMinutesFromNow.After(expiration) {
creds = nil
}
}
Expand Down Expand Up @@ -189,9 +189,9 @@ func CacheGetK8sConfigOutput(cacheKey string, tenantName string) (creds *clienta
// Check credentials for expiry.
if creds != nil {
// Expires in five minutes or less?
five_minutes_from_now := time.Now().UTC().Add(5 * time.Minute)
fiveMinutesFromNow := time.Now().UTC().Add(5 * time.Minute)
expiration := creds.Status.ExpirationTimestamp.Time
if five_minutes_from_now.After(expiration) {
if fiveMinutesFromNow.After(expiration) {
creds = nil
}
}
Expand Down
4 changes: 2 additions & 2 deletions internal/duplo.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ func duploClientAndOtpFlag(host, token, otp string, admin bool) (*duplocloud.Cli
}

// MustDuploClient retrieves a duplo client (and credentials) or panics.
func MustDuploClient(host, token string, interactive, admin bool) (client *duplocloud.Client, creds *DuploCredsOutput) {
func MustDuploClient(host, token string, interactive, admin bool, port int) (client *duplocloud.Client, creds *DuploCredsOutput) {
needsOtp := false
cacheKey := strings.TrimPrefix(host, "https://")

Expand Down Expand Up @@ -91,7 +91,7 @@ func MustDuploClient(host, token string, interactive, admin bool) (client *duplo
}

// Get the token, or fail.
tokenResult := MustTokenInteractive(host, admin, "duplo-jit")
tokenResult := MustTokenInteractive(host, admin, "duplo-jit", port)
if tokenResult.Token == "" {
log.Fatalf("%s: authentication failure: failed to get token interactively", os.Args[0])
}
Expand Down
8 changes: 4 additions & 4 deletions internal/interactive.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,10 +60,10 @@ func handlerTokenViaPost(baseUrl string, res http.ResponseWriter, req *http.Requ
return
}

func TokenViaPost(baseUrl string, admin bool, cmd string, timeout time.Duration) TokenResult {
func TokenViaPost(baseUrl string, admin bool, cmd string, port int, timeout time.Duration) TokenResult {

// Create the listener on a random port.
listener, err := net.Listen("tcp", "127.0.0.1:0")
listener, err := net.Listen("tcp", fmt.Sprintf("127.0.0.1:%d", port))
if err != nil {
return TokenResult{err: err}
}
Expand Down Expand Up @@ -127,8 +127,8 @@ func TokenViaPost(baseUrl string, admin bool, cmd string, timeout time.Duration)
}
}

func MustTokenInteractive(host string, admin bool, cmd string) (tokenResult TokenResult) {
tokenResult = TokenViaPost(host, admin, cmd, 180*time.Second)
func MustTokenInteractive(host string, admin bool, cmd string, port int) (tokenResult TokenResult) {
tokenResult = TokenViaPost(host, admin, cmd, port, 180*time.Second)
DieIf(tokenResult.err, "failed to get token from interactive browser session")
return
}
Loading

0 comments on commit 08dd6f4

Please sign in to comment.