feat(Microsoft Excel SharePoint Node): Add sign-in with person and app credentials (no-changelog) (#34089)

This commit is contained in:
Stephen Wright 2026-07-14 12:41:02 +01:00 committed by GitHub
parent 92541f1c5e
commit 93fa40c395
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 100 additions and 4 deletions

View File

@ -22,7 +22,51 @@ export class MicrosoftExcelSharePoint implements INodeType {
inputs: [NodeConnectionTypes.Main],
outputs: [NodeConnectionTypes.Main],
hidden: true,
properties: [],
// Legacy credentials deliberately excluded: the SharePoint one targets
// the old _api host (not Graph); the Excel one has no Sites.* scopes.
credentials: [
{
name: 'microsoftOAuth2Api',
required: true,
displayOptions: {
show: {
authentication: ['microsoftOAuth2Api'],
},
},
},
{
name: 'microsoftEntraServicePrincipalApi',
required: true,
displayOptions: {
show: {
authentication: ['microsoftEntraServicePrincipalApi'],
},
},
},
],
properties: [
{
displayName: 'Authentication',
name: 'authentication',
type: 'options',
noDataExpression: true,
options: [
{
name: 'Microsoft OAuth2 (Graph)',
value: 'microsoftOAuth2Api',
description:
'Generic Microsoft Graph credential. Enable the scopes this node needs (e.g. Sites.ReadWrite.All) on the credential.',
},
{
name: 'Microsoft Entra Service Principal (App-Only)',
value: 'microsoftEntraServicePrincipalApi',
description:
'App-only access via a Microsoft Entra app registration with admin-consented SharePoint application permissions',
},
],
default: 'microsoftOAuth2Api',
},
],
};
// Pass-through until the first action arrives with the router.

View File

@ -23,10 +23,11 @@ describe('MicrosoftExcelSharePoint (hidden shell)', () => {
expect(node.description.displayName).not.toBe(oneDriveNode.description.displayName);
});
it('should be a blank shell — no credentials, no properties', () => {
it('should stay a shell — sign-in only, no operations or tool exposure', () => {
expect(node.description.version).toBe(1);
expect(node.description.properties).toHaveLength(0);
expect(node.description.credentials).toBeUndefined();
// Any property beyond the sign-in selector would silently no-op through
// the pass-through execute; the first action ticket updates this bound.
expect(node.description.properties).toHaveLength(1);
expect(node.description.usableAsTool).toBeUndefined();
});

View File

@ -0,0 +1,51 @@
import { MicrosoftExcelSharePoint } from '../MicrosoftExcelSharePoint.node';
describe('Microsoft Excel (SharePoint) authentication selector', () => {
const { description } = new MicrosoftExcelSharePoint();
const properties = description.properties;
const credentials = description.credentials ?? [];
const authProperty = properties.find((property) => property.name === 'authentication');
const optionValues = (authProperty?.options ?? []).map((option) =>
'value' in option ? option.value : undefined,
);
it('should expose an authentication options selector as the first property', () => {
expect(authProperty).toBeDefined();
expect(authProperty?.type).toBe('options');
expect(authProperty?.noDataExpression).toBe(true);
expect(properties[0]?.name).toBe('authentication');
});
it('should offer exactly the generic Microsoft and Service Principal credentials', () => {
expect(optionValues).toEqual(['microsoftOAuth2Api', 'microsoftEntraServicePrincipalApi']);
});
it('should default to the generic Microsoft credential', () => {
expect(authProperty?.default).toBe('microsoftOAuth2Api');
});
it('should gate each credential behind its matching authentication value', () => {
expect(credentials).toHaveLength(2);
for (const credential of credentials) {
expect(credential.required).toBe(true);
expect(credential.displayOptions?.show?.authentication).toEqual([credential.name]);
}
});
it('should not offer the legacy SharePoint or Excel (OneDrive) credentials', () => {
const credentialNames = credentials.map((credential) => credential.name);
for (const legacyCredential of ['microsoftSharePointOAuth2Api', 'microsoftExcelOAuth2Api']) {
expect(optionValues).not.toContain(legacyCredential);
expect(credentialNames).not.toContain(legacyCredential);
}
});
it('should keep the default aligned with a gated credential', () => {
const credentialGatedByDefault = credentials.find((credential) =>
credential.displayOptions?.show?.authentication?.includes(authProperty?.default as string),
);
expect(credentialGatedByDefault?.name).toBe('microsoftOAuth2Api');
});
});