Skip to content

Commit

Permalink
Merge branch 'v3' into v3-data-formats
Browse files Browse the repository at this point in the history
  • Loading branch information
ecooper authored Dec 9, 2024
2 parents 55a6ab6 + fabed04 commit 311b947
Show file tree
Hide file tree
Showing 3 changed files with 125 additions and 38 deletions.
14 changes: 8 additions & 6 deletions src/lib/auth/databaseKeys.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@ const DEFAULT_ROLE = "admin";
*/
export class DatabaseKeys {
constructor(argv, accountKey) {
const { database } = argv;
this.path = argv.database;
this.role = argv.role || DEFAULT_ROLE;
this.keyName = DatabaseKeys.getKeyName(database, this.role);
this.keyName = DatabaseKeys.getKeyName(this.path, this.role);
this.keyStore = new SecretKeyStorage(accountKey);
this.ttlMs = TTL_DEFAULT_MS;

Expand Down Expand Up @@ -113,13 +113,15 @@ export class DatabaseKeys {
* @returns {string} - The new secret
*/
async refreshKey() {
this.logger.debug(`Creating new db key for ${this.keyName}`, "creds");
const [path, role] = this.keyName.split(":");
this.logger.debug(
`Creating new db key for path ${this.path} and role ${this.role}`,
"creds",
);
const expiration = this.getKeyExpiration();
const accountClient = new FaunaAccountClient();
const newSecret = await accountClient.createKey({
path,
role,
path: this.path,
role: this.role,
name: "System generated shell key",
ttl: new Date(expiration).toISOString(),
});
Expand Down
12 changes: 12 additions & 0 deletions test/credentials.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,18 @@ describe("credentials", function () {
},
},
},
{
command: `query "Database.all()" -d us-std/test:badpath --no-color`,
localCreds: defaultLocalCreds,
expected: {
databaseKeys: {
role: "admin",
path: "us-std/test:badpath",
key: undefined,
keySource: "credentials-file",
},
},
},
].forEach(({ command, expected, localCreds }) => {
it(`builds credentials from: '${command}'`, async () => {
setCredsFiles(localCreds.accountKeys, localCreds.databaseKeys);
Expand Down
137 changes: 105 additions & 32 deletions test/login.mjs
Original file line number Diff line number Diff line change
@@ -1,86 +1,159 @@
//@ts-check

import * as awilix from "awilix";
import { expect } from "chai";
import { stub } from "sinon";
import sinon, { spy } from "sinon";

import { run } from "../src/cli.mjs";
import { setupTestContainer as setupContainer } from "../src/config/setup-test-container.mjs";

describe("login", function () {
let container;
let fs;
const sessionCreds = {
accountKey: "account-key",
refreshToken: "refresh-token",
let container, fs, makeAccountRequest;
const mockOAuth = () => {
let handlers = {};

return {
_receiveAuthCode: spy(async () => {
await handlers.auth_code_received();
}),
start: spy(async () => {
await handlers.ready();
}),
getOAuthParams: () => {
return {
client_id: "client-id",
redirect_uri: "redirect-uri",
code_challenge: "challenge",
code_challenge_method: "S256",
response_type: "code",
scope: "create_session",
state: "state",
};
},
getTokenParams: () => {
return {
clientId: "client-id",
clientSecret: "client-secret",
authCode: "auth-code",
redirectURI: "redirect-uri",
codeVerifier: "code-verifier",
};
},
server: {
on: (eventName, handler) => {
handlers[eventName] = handler;
},
},
};
};

beforeEach(() => {
container = setupContainer();
container.register({
oauthClient: awilix.asFunction(mockOAuth).scoped(),
});
fs = container.resolve("fs");
makeAccountRequest = container.resolve("makeAccountRequest");
makeAccountRequest
.withArgs(
sinon.match({
path: sinon.match(/\/oauth\/authorize/),
method: "GET",
}),
)
.resolves({
headers: new Map([["location", "http://dashboard-url.com"]]),
status: 302,
})
.withArgs(
sinon.match({
path: sinon.match(/\/oauth\/token/),
method: "POST",
}),
)
.resolves({
access_token: "access-token",
})
.withArgs(
sinon.match({
path: sinon.match(/\/session/),
method: "POST",
}),
)
.resolves({
account_key: "login-account-key",
refresh_token: "login-refresh-token",
});
});

it.skip("can login", async function () {
// Run the command first so container is set.
await run(`login`, container);
// After container is set, we can get the mocks
const oauthClient = container.resolve("oauthClient");
const logger = container.resolve("logger");
const accountCreds = container.resolve("accountCreds");
it("can login", async function () {
const existingCreds = {
testProfile: {
testUser: {
accountKey: "test",
refreshToken: "test",
},
};
fs.readFileSync.returns(JSON.stringify(existingCreds));
// Run the command first so container is set.
await run(`login`, container);
// After container is set, we can get the mocks
const oauthClient = container.resolve("oauthClient");
const logger = container.resolve("logger");
const credentials = container.resolve("credentials");

const expectedCreds = {
...existingCreds,
default: sessionCreds,
default: {
accountKey: "login-account-key",
refreshToken: "login-refresh-token",
},
};

// We start the loopback server
expect(oauthClient.start.called).to.be.true;
// We open auth url in the browser and prompt user
expect(container.resolve("open").calledWith("dashboard-url"));
expect(container.resolve("open").calledWith("http://dashboard-url.com"));
expect(logger.stdout).to.have.been.calledWith(

Check failure on line 116 in test/login.mjs

View workflow job for this annotation

GitHub Actions / JUnit Test Report

/home/runner/work/fauna-shell/fauna-shell/test/login.mjs.login can login

expected stdout to have been called with arguments 'To login, open your browser to:\n http://dashboard-url.com' '"To login, open your browser to:\\nhttp://dashboard-url.com"' '"To login, open your browser to:\\n http://dashboard-url.com"'
Raw output
AssertionError: expected stdout to have been called with arguments 'To login, open your browser to:\n http://dashboard-url.com'
'"To login, open your browser to:\\nhttp://dashboard-url.com"' '"To login, open your browser to:\\n http://dashboard-url.com"' 
    at Context.<anonymous> (file:///home/runner/work/fauna-shell/fauna-shell/test/login.mjs:116:40)
"To login, open your browser to:\n dashboard-url",
"To login, open your browser to:\n http://dashboard-url.com",
);
accountCreds.get = stub().returns(existingCreds);
// Trigger server event with mocked auth code
await oauthClient._receiveAuthCode();
// Show login success message
expect(logger.stdout).to.have.been.calledWith("Login Success!\n");
expect(credentials.accountKeys.key).to.equal("login-account-key");
// We save the session credentials alongside existing credential contents
expect(accountCreds.filepath).to.include(".fauna/credentials/access_keys");
expect(JSON.parse(fs.writeFileSync.args[0][1])).to.deep.equal(
expect(fs.writeFileSync.getCall(1).args[0]).to.include("access_keys");
expect(JSON.parse(fs.writeFileSync.getCall(1).args[1])).to.deep.equal(
expectedCreds,
);
});

it.skip("overwrites credentials on login", async function () {
it("overwrites credentials on login", async function () {
const existingCreds = {
testProfile: {
testUser: {
accountKey: "oldkey",
refreshToken: "oldtoken",
},
};

// Local file read returns old creds
fs.readFileSync.returns(JSON.stringify(existingCreds));
await run(`login --user testUser`, container);
const oauthClient = container.resolve("oauthClient");
const logger = container.resolve("logger");
const expectedCreds = {
testProfile: {
accountKey: "account-key",
refreshToken: "refresh-token",
testUser: {
accountKey: "login-account-key",
refreshToken: "login-refresh-token",
},
};
await run(`login --profile testProfile`, container);
const accountCreds = container.resolve("accountCreds");
const oauthClient = container.resolve("oauthClient");
const logger = container.resolve("logger");
// Local file read returns old creds
accountCreds.get = stub().returns(existingCreds);
// Trigger server event with mocked auth code
await oauthClient._receiveAuthCode();
// Show login success message
expect(logger.stdout).to.have.been.calledWith("Login Success!\n");

Check failure on line 153 in test/login.mjs

View workflow job for this annotation

GitHub Actions / JUnit Test Report

/home/runner/work/fauna-shell/fauna-shell/test/login.mjs.login overwrites credentials on login

expected stdout to have been called with arguments 'Login Success!\n' '"To login, open your browser to:\\nhttp://dashboard-url.com"' '"Login Success!\\n"'
Raw output
AssertionError: expected stdout to have been called with arguments 'Login Success!\n'
'"To login, open your browser to:\\nhttp://dashboard-url.com"' '"Login Success!\\n"' 
    at Context.<anonymous> (file:///home/runner/work/fauna-shell/fauna-shell/test/login.mjs:153:40)
// We save the session credentials and overwrite the profile of the same name locally
expect(JSON.parse(fs.writeFileSync.args[0][1])).to.deep.equal(
expect(fs.writeFileSync.getCall(1).args[0]).to.include("access_keys");
expect(JSON.parse(fs.writeFileSync.getCall(1).args[1])).to.deep.equal(
expectedCreds,
);
});
Expand Down

0 comments on commit 311b947

Please sign in to comment.