Files
zeekay 38451edec0 Add Drive to the Workspace add-on
A drive homepage trigger and an onItemsSelectedTrigger put Hanzo beside
the files selected in Drive: summarize them, ask about them, or draft a
new Google Doc from them. The add-on holds drive.file, granted per file
from the card, and drive.addons.metadata.readonly, never the restricted
drive or drive.readonly scopes; validate and the tests refuse any
broader Drive scope. DriveApp needs the full drive scope, so files are
read and Docs created through the Drive REST API.
2026-09-30 14:53:58 -07:00

87 lines
3.4 KiB
JavaScript

import { describe, it, expect } from 'vitest';
import { readFileSync } from 'node:fs';
import { fileURLToPath } from 'node:url';
import { dirname, resolve } from 'node:path';
const here = dirname(fileURLToPath(import.meta.url));
const manifest = JSON.parse(
readFileSync(resolve(here, '..', 'src', 'appsscript.json'), 'utf8')
);
describe('appsscript.json', () => {
it('is V8 with Stackdriver logging', () => {
expect(manifest.runtimeVersion).toBe('V8');
expect(manifest.exceptionLogging).toBe('STACKDRIVER');
});
it('declares the per-host currentonly scopes + external_request', () => {
const scopes = manifest.oauthScopes;
expect(scopes).toContain('https://www.googleapis.com/auth/documents.currentonly');
expect(scopes).toContain('https://www.googleapis.com/auth/spreadsheets.currentonly');
expect(scopes).toContain('https://www.googleapis.com/auth/presentations.currentonly');
expect(scopes).toContain('https://www.googleapis.com/auth/script.external_request');
});
it('declares the Gmail add-on scopes (read message + compose action)', () => {
const scopes = manifest.oauthScopes;
expect(scopes).toContain(
'https://www.googleapis.com/auth/gmail.addons.current.message.readonly'
);
expect(scopes).toContain(
'https://www.googleapis.com/auth/gmail.addons.current.action.compose'
);
});
it('whitelists api.hanzo.ai and the Drive API, nothing else, for UrlFetch', () => {
expect(manifest.urlFetchWhitelist).toEqual([
'https://api.hanzo.ai/',
'https://www.googleapis.com/drive/v3/',
'https://www.googleapis.com/upload/drive/v3/',
]);
});
it('holds only per-file Drive scopes, never the restricted drive / drive.readonly', () => {
const drive = manifest.oauthScopes.filter((s) => s.startsWith('https://www.googleapis.com/auth/drive'));
expect(drive.sort()).toEqual([
'https://www.googleapis.com/auth/drive.addons.metadata.readonly',
'https://www.googleapis.com/auth/drive.file',
]);
});
it('registers a homepage trigger for every host', () => {
const addOns = manifest.addOns;
expect(addOns.common.homepageTrigger.runFunction).toBe('onHomepage');
expect(addOns.docs.homepageTrigger.runFunction).toBe('onDocsHomepage');
expect(addOns.sheets.homepageTrigger.runFunction).toBe('onSheetsHomepage');
expect(addOns.slides.homepageTrigger.runFunction).toBe('onSlidesHomepage');
expect(addOns.gmail.homepageTrigger.runFunction).toBe('onGmailHomepage');
expect(addOns.drive.homepageTrigger.runFunction).toBe('onDriveHomepage');
});
it('wires the Drive selection trigger', () => {
expect(manifest.addOns.drive.onItemsSelectedTrigger.runFunction).toBe('onDriveItemsSelected');
});
it('wires the Gmail contextual + compose triggers', () => {
const gmail = manifest.addOns.gmail;
expect(gmail.contextualTriggers[0].onTriggerFunction).toBe('onGmailMessage');
expect(gmail.composeTrigger.selectActions[0].runFunction).toBe('onGmailCompose');
});
it('exposes the Hanzo account universal action', () => {
expect(manifest.addOns.common.universalActions).toEqual([
{ label: 'Hanzo account', runFunction: 'onSettings' },
]);
});
it('signs in through the OAuth2 for Apps Script library', () => {
expect(manifest.dependencies.libraries).toEqual([
{
userSymbol: 'OAuth2',
libraryId: '1B7FSrk5Zi6L1rSxxTDgDEUsPzlukDsi4KGuTMorsTQHhGBzBkMun4iDF',
version: '43',
},
]);
});
});