Skip to content

Commit

Permalink
feat(platform): support non-interactive auth
Browse files Browse the repository at this point in the history
Added support for non-interactive authentication with the platform
via a new environment variable: `GARDEN_AUTH_TOKEN`.

In some contexts where interactive login is not feasible (e.g. CI),
a valid client auth token may still be available before logging in,

Furthermore, storing the client auth token in the local config DB is not
always desirable in these contexts.

To handle these situations, a client auth token can now be provided to
garden commands making use of platform features (such as secrets)
by populating the `GARDEN_AUTH_TOKEN` environment variable with the
client auth token before running the command.
  • Loading branch information
thsig authored and edvald committed Jun 24, 2020
1 parent e5023f7 commit b020593
Show file tree
Hide file tree
Showing 7 changed files with 92 additions and 1 deletion.
11 changes: 10 additions & 1 deletion garden-service/src/cloud/auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -100,12 +100,21 @@ export async function saveAuthToken(token: string, log: LogEntry) {
}

/**
* If a persisted client auth token was found, returns it. Returns null otherwise.
* If a persisted client auth token was found, or if the GARDEN_AUTH_TOKEN environment variable is present, returns it.
* Returns null otherwise.
*
* Note that the GARDEN_AUTH_TOKEN environment variable takes precedence over a persisted auth token if both are
* present.
*
* In the inconsistent/erroneous case of more than one auth token existing in the local store, picks the first auth
* token and deletes all others.
*/
export async function readAuthToken(log: LogEntry): Promise<string | null> {
const tokenFromEnv = process.env.GARDEN_AUTH_TOKEN
if (tokenFromEnv) {
return tokenFromEnv
}

const [tokens, tokenCount] = await ClientAuthToken.findAndCount()

const token = tokens[0] ? tokens[0].token : null
Expand Down
14 changes: 14 additions & 0 deletions garden-service/test/data/cloud/garden.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
kind: Project
name: cloud
id: test-project-id
domain: test.cloud.com
environments:
- name: local
- name: other
providers:
- name: test-plugin
environments: [local]
- name: test-plugin-b
environments: [local]
variables:
some: variable
3 changes: 3 additions & 0 deletions garden-service/test/data/cloud/module-a/.garden-version
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"contentHash": "1234567890"
}
17 changes: 17 additions & 0 deletions garden-service/test/data/cloud/module-a/garden.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
kind: Module
name: module-a
type: test
services:
- name: service-a
build:
command: [echo, A]
tests:
- name: unit
command: [echo, OK]
- name: integration
command: [echo, OK]
dependencies:
- service-a
tasks:
- name: task-a
command: [echo, OK]
17 changes: 17 additions & 0 deletions garden-service/test/data/cloud/module-b/garden.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
kind: Module
name: module-b
type: test
services:
- name: service-b
dependencies:
- service-a
build:
command: [echo, B]
dependencies:
- module-a
tests:
- name: unit
command: [echo, OK]
tasks:
- name: task-b
command: [echo, OK]
17 changes: 17 additions & 0 deletions garden-service/test/data/cloud/module-c/garden.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
kind: Module
name: module-c
type: test
services:
- name: service-c
dependencies: [task-c]
build:
dependencies:
- module-b
tests:
- name: unit
command: [echo, OK]
- name: integ
command: [echo, OK]
tasks:
- name: task-c
command: [echo, OK]
14 changes: 14 additions & 0 deletions garden-service/test/unit/src/cloud/auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { expect } from "chai"
import { ClientAuthToken } from "../../../../src/db/entities/client-auth-token"
import { makeTestGardenA } from "../../../helpers"
import { saveAuthToken, readAuthToken, clearAuthToken } from "../../../../src/cloud/auth"
import { getLogger } from "../../../../src/logger/logger"

async function cleanupAuthTokens() {
await ClientAuthToken.createQueryBuilder()
Expand Down Expand Up @@ -63,6 +64,19 @@ describe("cloud", () => {
expect(savedToken).to.eql("test-token")
})

it("should return the value of GARDEN_AUTH_TOKEN if it's present", async () => {
const envBackup = { ...process.env }
const testToken = "token-from-env"
process.env.GARDEN_AUTH_TOKEN = testToken
const log = getLogger().placeholder()
try {
const savedToken = await readAuthToken(log)
expect(savedToken).to.eql(testToken)
} finally {
process.env = envBackup
}
})

it("should clean up duplicate auth tokens in the erroneous case when several exist", async () => {
const garden = await makeTestGardenA()
await Bluebird.map(["token-1", "token-2", "token-3"], async (token) => {
Expand Down

0 comments on commit b020593

Please sign in to comment.