Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adds 'm365 entra resourcenamespace list' command. Closes #6561 #6583

Closed
wants to merge 2 commits into from
Closed
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
96 changes: 96 additions & 0 deletions docs/docs/cmd/entra/resourcenamespace/resourcenamespace-list.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
import Global from '/docs/cmd/_global.mdx';
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

# entra resourcenamespace list

Get a list of the RBAC resource namespaces and their properties

## Usage

```sh
m365 entra resourcenamespace list [options]
```

## Options

<Global />

## Remarks

:::warning

The command is based on an API that is currently in preview and is subject to change once the API reached general availability.

:::

## Examples

Retrieve all resource namespaces.

```sh
m365 entra resourcenamespace list
```

## Response

<Tabs>
<TabItem value="JSON">

```json
[
{
"id": "microsoft.directory",
"name": "microsoft.directory"
},
{
"id": "microsoft.aad.b2c",
"name": "microsoft.aad.b2c"
}
]
```

</TabItem>
<TabItem value="Text">

```text
id name
-------------------- --------------------
microsoft.directory microsoft.directory
microsoft.aad.b2c microsoft.aad.b2c
```

</TabItem>
<TabItem value="CSV">

```csv
id,name
microsoft.directory,microsoft.directory
microsoft.aad.b2c,microsoft.aad.b2c
```

</TabItem>
<TabItem value="Markdown">

```md
# entra resourcenamespace list

Date: 1/31/2025

## microsoft.directory (microsoft.directory)

Property | Value
---------|-------
id | microsoft.directory
name | microsoft.directory

## microsoft.aad.b2c (microsoft.aad.b2c)

Property | Value
---------|-------
id | microsoft.aad.b2c
name | microsoft.aad.b2c
```

</TabItem>
</Tabs>
9 changes: 9 additions & 0 deletions docs/src/config/sidebars.ts
Original file line number Diff line number Diff line change
Expand Up @@ -632,6 +632,15 @@ const sidebars: SidebarsConfig = {
}
]
},
{
resourcenamespace: [
{
type: 'doc',
label: 'resourcenamespace list',
id: 'cmd/entra/resourcenamespace/resourcenamespace-list'
}
]
},
{
roledefinition: [
{
Expand Down
1 change: 1 addition & 0 deletions src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ export default {
'https://graph.microsoft.com/Reports.ReadWrite.All',
'https://graph.microsoft.com/RoleAssignmentSchedule.ReadWrite.Directory',
'https://graph.microsoft.com/RoleEligibilitySchedule.Read.Directory',
'https://graph.microsoft.com/RoleManagement.Read.Directory',
'https://graph.microsoft.com/SecurityEvents.Read.All',
'https://graph.microsoft.com/ServiceHealth.Read.All',
'https://graph.microsoft.com/ServiceMessage.Read.All',
Expand Down
1 change: 1 addition & 0 deletions src/m365/entra/commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ export default {
PIM_ROLE_ASSIGNMENT_ELIGIBILITY_LIST: `${prefix} pim role assignment eligibility list`,
PIM_ROLE_REQUEST_LIST: `${prefix} pim role request list`,
POLICY_LIST: `${prefix} policy list`,
RESOURCENAMESPACE_LIST: `${prefix} resourcenamespace list`,
ROLEDEFINITION_ADD: `${prefix} roledefinition add`,
ROLEDEFINITION_LIST: `${prefix} roledefinition list`,
ROLEDEFINITION_GET: `${prefix} roledefinition get`,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
import assert from 'assert';
import sinon from 'sinon';
import auth from '../../../../Auth.js';
import { Logger } from '../../../../cli/Logger.js';
import { CommandError } from '../../../../Command.js';
import request from '../../../../request.js';
import { telemetry } from '../../../../telemetry.js';
import { pid } from '../../../../utils/pid.js';
import { session } from '../../../../utils/session.js';
import { sinonUtil } from '../../../../utils/sinonUtil.js';
import commands from '../../commands.js';
import command from './resourcenamespace-list.js';


describe(commands.RESOURCENAMESPACE_LIST, () => {
let log: string[];
let logger: Logger;
let loggerLogSpy: sinon.SinonSpy;

before(() => {
sinon.stub(auth, 'restoreAuth').resolves();
sinon.stub(telemetry, 'trackEvent').returns();
sinon.stub(pid, 'getProcessName').returns('');
sinon.stub(session, 'getId').returns('');
auth.connection.active = true;
});

beforeEach(() => {
log = [];
logger = {
log: async (msg: string) => {
log.push(msg);
},
logRaw: async (msg: string) => {
log.push(msg);
},
logToStderr: async (msg: string) => {
log.push(msg);
}
};
loggerLogSpy = sinon.spy(logger, 'log');
});

afterEach(() => {
sinonUtil.restore([
request.get
]);
});

after(() => {
sinon.restore();
auth.connection.active = false;
});

it('has correct name', () => {
assert.strictEqual(command.name, commands.RESOURCENAMESPACE_LIST);
});

it('has a description', () => {
assert.notStrictEqual(command.description, null);
});

it('defines correct properties for the default output', () => {
assert.deepStrictEqual(command.defaultProperties(), ['id', 'name']);
});

it(`should get a list of resource namespaces`, async () => {
sinon.stub(request, 'get').callsFake(async (opts) => {
if (opts.url === `https://graph.microsoft.com/beta/roleManagement/directory/resourceNamespaces`) {
return {
value: [
{
"id": "microsoft.directory",
"name": "microsoft.directory"
},
{
"id": "microsoft.aad.b2c",
"name": "microsoft.aad.b2c"
}
]
};
}

throw 'Invalid request';
});

await command.action(logger, {
options: { verbose: true }
});

assert(
loggerLogSpy.calledWith([
{
"id": "microsoft.directory",
"name": "microsoft.directory"
},
{
"id": "microsoft.aad.b2c",
"name": "microsoft.aad.b2c"
}
])
);
});

it('handles error when retrieving a list of resource namespaces failed', async () => {
sinon.stub(request, 'get').callsFake(async (opts) => {
if (opts.url === `https://graph.microsoft.com/beta/roleManagement/directory/resourceNamespaces`) {
throw { error: { message: 'An error has occurred' } };
}
throw `Invalid request`;
});

await assert.rejects(
command.action(logger, { options: {} } as any),
new CommandError('An error has occurred')
);
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { Logger } from '../../../../cli/Logger.js';
import { odata } from '../../../../utils/odata.js';
import GraphCommand from '../../../base/GraphCommand.js';
import commands from '../../commands.js';

class EntraResourcenamespaceListCommand extends GraphCommand {
public get name(): string {
return commands.RESOURCENAMESPACE_LIST;
}

public get description(): string {
return 'Get a list of the RBAC resource namespaces and their properties';
}

public defaultProperties(): string[] | undefined {
return ['id', 'name'];
}

public async commandAction(logger: Logger): Promise<void> {
if (this.verbose) {
await logger.logToStderr('Getting a list of the RBAC resource namespaces and their properties...');
}

try {
const results = await odata.getAllItems<{ id: string, name: string }>(`${this.resource}/beta/roleManagement/directory/resourceNamespaces`);
await logger.log(results);
}
catch (err: any) {
this.handleRejectedODataJsonPromise(err);
}
}
}

export default new EntraResourcenamespaceListCommand();
Loading