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
83 changes: 83 additions & 0 deletions client/packages/cli/__tests__/e2e/cli.e2e.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1010,6 +1010,89 @@ export default _schema;
}
});

it('--as-token runs query as a user identified by refresh token', async () => {
const { appId, adminToken } = await createTempApp();

const schemaWithCreator = `
import { i } from "@instantdb/core";
const _schema = i.schema({
entities: {
posts: i.entity({
title: i.string(),
creatorEmail: i.string(),
}),
},
});
export default _schema;
`;

const restrictedPerms = `export default {
posts: {
allow: {
view: "auth.email == data.creatorEmail",
},
},
};
`;

const project = await createTestProject({
appId,
schemaFile: schemaWithCreator,
permsFile: restrictedPerms,
});

try {
const pushResult = await runCli(['push', '--yes'], {
cwd: project.dir,
env: {
INSTANT_CLI_AUTH_TOKEN: adminToken,
INSTANT_APP_ID: appId,
},
});
expect(pushResult.exitCode).toBe(0);

const alice = await createAppUser(appId, adminToken, 'alice@test.com');

await adminTransact(appId, adminToken, [
[
'update',
'posts',
randomUUID(),
{ title: "Alice's Post", creatorEmail: 'alice@test.com' },
],
[
'update',
'posts',
randomUUID(),
{ title: "Bob's Post", creatorEmail: 'bob@test.com' },
],
]);

// Using Alice's refresh token should only show Alice's post
const result = await runCli(
[
'query',
'--as-token',
alice.refreshToken,
JSON.stringify({ posts: {} }),
],
{
cwd: project.dir,
env: {
INSTANT_CLI_AUTH_TOKEN: adminToken,
INSTANT_APP_ID: appId,
},
},
);
expect(result.exitCode).toBe(0);
const data = JSON.parse(result.stdout);
expect(data.posts).toHaveLength(1);
expect(data.posts[0].title).toBe("Alice's Post");
} finally {
await project.cleanup();
}
});

it('--as-guest runs query as unauthenticated user', async () => {
const { appId, adminToken } = await createTempApp();

Expand Down
18 changes: 14 additions & 4 deletions client/packages/cli/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -596,6 +596,10 @@ program
.option('--admin', 'Run the query as admin (bypasses permissions)')
.option('--as-email <email>', 'Run the query as a specific user by email')
.option('--as-guest', 'Run the query as an unauthenticated guest')
.option(
'--as-token <refresh-token>',
'Run the query as a user identified by refresh token',
)
.description('Run an InstaQL query against your app.')
.action(async function (queryArg, opts) {
await handleQuery(queryArg, opts);
Expand Down Expand Up @@ -716,11 +720,15 @@ async function detectAppIdQuietly(opts) {
}

async function handleQuery(queryArg, opts) {
const contextCount =
(opts.admin ? 1 : 0) + (opts.asEmail ? 1 : 0) + (opts.asGuest ? 1 : 0);
if (contextCount > 1) {
const contexts = [
opts.admin,
opts.asEmail,
opts.asGuest,
opts.asToken,
].filter(Boolean);
if (contexts.length > 1) {
error(
'Please specify exactly one context: --admin, --as-email <email>, or --as-guest',
'Please specify exactly one context: --admin, --as-email <email>, --as-guest, or --as-token <refresh-token>',
);
return process.exit(1);
}
Expand All @@ -747,6 +755,8 @@ async function handleQuery(queryArg, opts) {
headers['as-email'] = opts.asEmail;
} else if (opts.asGuest) {
headers['as-guest'] = 'true';
} else if (opts.asToken) {
headers['as-token'] = opts.asToken;
}

const res = await fetchJson({
Expand Down
2 changes: 1 addition & 1 deletion client/packages/version/src/version.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@
// Update the version here and merge your code to main to
// publish a new version of all of the packages to npm.

const version = 'v0.22.168';
const version = 'v0.22.169';

export { version };
1 change: 1 addition & 0 deletions client/www/pages/docs/cli.md
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ Each query requires an auth context flag:
- `--admin` bypasses permissions (default)
- `--as-email <email>` runs the query as a specific user with permissions applied
- `--as-guest` runs the query as an unauthenticated guest
- `--as-token <refresh-token>` runs the query as a user identified by their refresh token

For example, to see what a specific user can access:

Expand Down
Loading