Skip to content

Commit

Permalink
Add new command 'purview threatassessment get'. Closes #4427
Browse files Browse the repository at this point in the history
  • Loading branch information
MathijsVerbeeck authored and martinlingstuyl committed Apr 5, 2023
1 parent 600b4c0 commit c6a243c
Show file tree
Hide file tree
Showing 6 changed files with 447 additions and 1 deletion.
2 changes: 2 additions & 0 deletions .eslintrc.js
Expand Up @@ -10,6 +10,7 @@ const dictionary = [
'application',
'apply',
'approve',
'assessment',
'assets',
'audit',
'bin',
Expand Down Expand Up @@ -84,6 +85,7 @@ const dictionary = [
'storage',
'table',
'teams',
'threat',
'token',
'type',
'user',
Expand Down
191 changes: 191 additions & 0 deletions docs/docs/cmd/purview/threatassessment/threatassessment-get.md
@@ -0,0 +1,191 @@
# purview threatassessment get

Get a threat assessment

## Usage

```sh
m365 purview threatassessment get [options]
```

## Options

`-i, --id <id>`
: The Id of the threat assessment

`--includeResults`
: Include the threat assessment results

--8<-- "docs/cmd/_global.md"

## Examples

Get a threat assessment

```sh
m365 purview threatassessment get --id c37d695e-d581-4ae9-82a0-9364eba4291e
```

Get a threat assessment including results

```sh
m365 purview threatassessment get --id c37d695e-d581-4ae9-82a0-9364eba4291e --includeResults
```

## Response

### Standard Response

=== "JSON"

```json
{
"id": "8aaba0ac-ec4d-4e62-5774-08db16c68731",
"createdDateTime": "2023-02-25T00:23:33.0550644Z",
"contentType": "mail",
"expectedAssessment": "block",
"category": "spam",
"status": "pending",
"requestSource": "administrator",
"recipientEmail": "john@contoso.com",
"destinationRoutingReason": "notJunk",
"messageUri": "https://graph.microsoft.com/v1.0/users/john@contoso.com/messages/AAMkADgzN2Q1NThiLTI0NjYtNGIxYS05MDdjLTg1OWQxNzgwZGM2ZgBGAAAAAAC6jQfUzacTSIHqMw2yacnUBwBiOC8xvYmdT6G2E_hLMK5kAAAAAAEMAABiOC8xvYmdT6G2E_hLMK5kAALHNaMuAAA=",
"createdBy": {
"user": {
"id": "fe36f75e-c103-410b-a18a-2bf6df06ac3a",
"displayName": "John Doe"
}
}
}
```

=== "Text"

```text
category : spam
contentType : mail
createdBy : {"user":{"id":"fe36f75e-c103-410b-a18a-2bf6df06ac3a","displayName":"John Doe"}}
createdDateTime : 2023-02-25T00:23:33.0550644Z
destinationRoutingReason: notJunk
expectedAssessment : block
id : 8aaba0ac-ec4d-4e62-5774-08db16c68731
messageUri : https://graph.microsoft.com/v1.0/users/john@contoso.com/messages/AAMkADgzN2Q1NThiLTI0NjYtNGIxYS05MDdjLTg1OWQxNzgwZGM2ZgBGAAAAAAC6jQfUzacTSIHqMw2yacnUBwBiOC8xvYmdT6G2E_hLMK5kAAAAAAEMAABiOC8xvYmdT6G2E_hLMK5kAALHNaMuAAA=
recipientEmail : john@contoso.com
requestSource : administrator
status : pending
```

=== "CSV"

```csv
id,createdDateTime,contentType,expectedAssessment,category,status,requestSource,recipientEmail,destinationRoutingReason,messageUri,createdBy
8aaba0ac-ec4d-4e62-5774-08db16c68731,2023-02-25T00:23:33.0550644Z,mail,block,spam,pending,administrator,john@contoso.com,notJunk,https://graph.microsoft.com/v1.0/users/john@contoso.com/messages/AAMkADgzN2Q1NThiLTI0NjYtNGIxYS05MDdjLTg1OWQxNzgwZGM2ZgBGAAAAAAC6jQfUzacTSIHqMw2yacnUBwBiOC8xvYmdT6G2E_hLMK5kAAAAAAEMAABiOC8xvYmdT6G2E_hLMK5kAALHNaMuAAA=,"{""user"":{""id"":""fe36f75e-c103-410b-a18a-2bf6df06ac3a"",""displayName"":""John Doe""}}"
```

=== "Markdown"

```md
# purview threatassessment get --id "8aaba0ac-ec4d-4e62-5774-08db16c68731"

Date: 25/02/2023

## 8aaba0ac-ec4d-4e62-5774-08db16c68731

Property | Value
---------|-------
id | 8aaba0ac-ec4d-4e62-5774-08db16c68731
createdDateTime | 2023-02-25T00:23:33.0550644Z
contentType | mail
expectedAssessment | block
category | spam
status | pending
requestSource | administrator
recipientEmail | john@contoso.com
destinationRoutingReason | notJunk
messageUri | https://graph.microsoft.com/v1.0/users/john@contoso.com/messages/AAMkADgzN2Q1NThiLTI0NjYtNGIxYS05MDdjLTg1OWQxNzgwZGM2ZgBGAAAAAAC6jQfUzacTSIHqMw2yacnUBwBiOC8xvYmdT6G2E\_hLMK5kAAAAAAEMAABiOC8xvYmdT6G2E\_hLMK5kAALHNaMuAAA=
createdBy | {"user":{"id":"fe36f75e-c103-410b-a18a-2bf6df06ac3a","displayName":"John Doe"}}
```

### `includeResults` response

When we make use of the option `includeResults` the response will differ.

=== "JSON"

```json
{
"id": "8aaba0ac-ec4d-4e62-5774-08db16c68731",
"createdDateTime": "2023-02-25T00:23:33.0550644Z",
"contentType": "mail",
"expectedAssessment": "block",
"category": "spam",
"status": "pending",
"requestSource": "administrator",
"recipientEmail": "john@contoso.com",
"destinationRoutingReason": "notJunk",
"messageUri": "https://graph.microsoft.com/v1.0/users/john@contoso.com/messages/AAMkADgzN2Q1NThiLTI0NjYtNGIxYS05MDdjLTg1OWQxNzgwZGM2ZgBGAAAAAAC6jQfUzacTSIHqMw2yacnUBwBiOC8xvYmdT6G2E_hLMK5kAAAAAAEMAABiOC8xvYmdT6G2E_hLMK5kAALHNaMuAAA=",
"createdBy": {
"user": {
"id": "fe36f75e-c103-410b-a18a-2bf6df06ac3a",
"displayName": "John Doe"
}
},
"results": [
{
"id": "a5455871-18d1-44d8-0866-08db16c68b85",
"createdDateTime": "2023-02-25T00:23:40.28Z",
"resultType": "checkPolicy",
"message": "No policy was hit."
}
]
}
```

=== "Text"

```text
category : spam
contentType : mail
createdBy : {"user":{"id":"fe36f75e-c103-410b-a18a-2bf6df06ac3a","displayName":"John Doe"}}
createdDateTime : 2023-02-25T00:23:33.0550644Z
destinationRoutingReason: notJunk
expectedAssessment : block
id : 8aaba0ac-ec4d-4e62-5774-08db16c68731
messageUri : https://graph.microsoft.com/v1.0/users/john@contoso.com/messages/AAMkADgzN2Q1NThiLTI0NjYtNGIxYS05MDdjLTg1OWQxNzgwZGM2ZgBGAAAAAAC6jQfUzacTSIHqMw2yacnUBwBiOC8xvYmdT6G2E_hLMK5kAAAAAAEMAABiOC8xvYmdT6G2E_hLMK5kAALHNaMuAAA=
recipientEmail : john@contoso.com
requestSource : administrator
results : [{"id":"a5455871-18d1-44d8-0866-08db16c68b85","createdDateTime":"2023-02-25T00:23:40.28Z","resultType":"checkPolicy","message":"No policy was hit."}]
status : pending
```

=== "CSV"

```csv
id,createdDateTime,contentType,expectedAssessment,category,status,requestSource,recipientEmail,destinationRoutingReason,messageUri,createdBy,results
8aaba0ac-ec4d-4e62-5774-08db16c68731,2023-02-25T00:23:33.0550644Z,mail,block,spam,pending,administrator,john@contoso.com,notJunk,https://graph.microsoft.com/v1.0/users/john@contoso.com/messages/AAMkADgzN2Q1NThiLTI0NjYtNGIxYS05MDdjLTg1OWQxNzgwZGM2ZgBGAAAAAAC6jQfUzacTSIHqMw2yacnUBwBiOC8xvYmdT6G2E_hLMK5kAAAAAAEMAABiOC8xvYmdT6G2E_hLMK5kAALHNaMuAAA=,"{""user"":{""id"":""fe36f75e-c103-410b-a18a-2bf6df06ac3a"",""displayName"":""John Doe""}}","[{""id"":""a5455871-18d1-44d8-0866-08db16c68b85"",""createdDateTime"":""2023-02-25T00:23:40.28Z"",""resultType"":""checkPolicy"",""message"":""No policy was hit.""}]"
```

=== "Markdown"

```md
# purview threatassessment get --id "8aaba0ac-ec4d-4e62-5774-08db16c68731" --includeResults "true"

Date: 25/02/2023

## 8aaba0ac-ec4d-4e62-5774-08db16c68731

Property | Value
---------|-------
id | 8aaba0ac-ec4d-4e62-5774-08db16c68731
createdDateTime | 2023-02-25T00:23:33.0550644Z
contentType | mail
expectedAssessment | block
category | spam
status | pending
requestSource | administrator
recipientEmail | john@contoso.com
destinationRoutingReason | notJunk
messageUri | https://graph.microsoft.com/v1.0/users/john@contoso.com/messages/AAMkADgzN2Q1NThiLTI0NjYtNGIxYS05MDdjLTg1OWQxNzgwZGM2ZgBGAAAAAAC6jQfUzacTSIHqMw2yacnUBwBiOC8xvYmdT6G2E\_hLMK5kAAAAAAEMAABiOC8xvYmdT6G2E\_hLMK5kAALHNaMuAAA=
createdBy | {"user":{"id":"fe36f75e-c103-410b-a18a-2bf6df06ac3a","displayName":"John Doe"}}
results | [{"id":"a5455871-18d1-44d8-0866-08db16c68b85","createdDateTime":"2023-02-25T00:23:40.28Z","resultType":"checkPolicy","message":"No policy was hit."}]
```
2 changes: 2 additions & 0 deletions docs/mkdocs.yml
Expand Up @@ -353,6 +353,8 @@ nav:
- retentionlabel list: cmd/purview/retentionlabel/retentionlabel-list.md
- retentionlabel remove: cmd/purview/retentionlabel/retentionlabel-remove.md
- retentionlabel set: cmd/purview/retentionlabel/retentionlabel-set.md
- threatassessment:
- threatassessment get: cmd/purview/threatassessment/threatassessment-get.md
- Search (search):
- externalconnection:
- externalconnection add: cmd/search/externalconnection/externalconnection-add.md
Expand Down
3 changes: 2 additions & 1 deletion src/m365/purview/commands.ts
Expand Up @@ -15,5 +15,6 @@ export default {
RETENTIONLABEL_GET: `${prefix} retentionlabel get`,
RETENTIONLABEL_LIST: `${prefix} retentionlabel list`,
RETENTIONLABEL_REMOVE: `${prefix} retentionlabel remove`,
RETENTIONLABEL_SET: `${prefix} retentionlabel set`
RETENTIONLABEL_SET: `${prefix} retentionlabel set`,
THREATASSESSMENT_GET: `${prefix} threatassessment get`
};
@@ -0,0 +1,163 @@
import * as assert from 'assert';
import * as sinon from 'sinon';
import { telemetry } from '../../../../telemetry';
import auth from '../../../../Auth';
import { Logger } from '../../../../cli/Logger';
import Command, { CommandError } from '../../../../Command';
import request from '../../../../request';
import { pid } from '../../../../utils/pid';
import { session } from '../../../../utils/session';
import { sinonUtil } from '../../../../utils/sinonUtil';
import commands from '../../commands';
import { CommandInfo } from '../../../../cli/CommandInfo';
import { Cli } from '../../../../cli/Cli';
const command: Command = require('./threatassessment-get');

describe(commands.THREATASSESSMENT_GET, () => {
const threatAssessmentId = 'c37d695e-d581-4ae9-82a0-9364eba4291e';
const threatAssessmentGetResponse = {
'id': '8aaba0ac-ec4d-4e62-5774-08db16c68731',
'createdDateTime': '2023-02-25T00:23:33.0550644Z',
'contentType': 'mail',
'expectedAssessment': 'block',
'category': 'spam',
'status': 'pending',
'requestSource': 'administrator',
'recipientEmail': 'john@contoso.com',
'destinationRoutingReason': 'notJunk',
'messageUri': 'https://graph.microsoft.com/v1.0/users/john@contoso.com/messages/AAMkADgzN2Q1NThiLTI0NjYtNGIxYS05MDdjLTg1OWQxNzgwZGM2ZgBGAAAAAAC6jQfUzacTSIHqMw2yacnUBwBiOC8xvYmdT6G2E_hLMK5kAAAAAAEMAABiOC8xvYmdT6G2E_hLMK5kAALHNaMuAAA=',
'createdBy': {
'user': {
'id': 'fe36f75e-c103-410b-a18a-2bf6df06ac3a',
'displayName': 'John Doe'
}
}
};

const threatAssessmentGetResponseIncludingResults = {
...threatAssessmentGetResponse,
'results': [
{
'id': 'a5455871-18d1-44d8-0866-08db16c68b85',
'createdDateTime': '2023-02-25T00:23:40.28Z',
'resultType': 'checkPolicy',
'message': 'No policy was hit.'
}
]
};

let log: string[];
let logger: Logger;
let loggerLogSpy: sinon.SinonSpy;
let commandInfo: CommandInfo;

before(() => {
sinon.stub(auth, 'restoreAuth').callsFake(() => Promise.resolve());
sinon.stub(telemetry, 'trackEvent').callsFake(() => { });
sinon.stub(pid, 'getProcessName').callsFake(() => '');
sinon.stub(session, 'getId').callsFake(() => '');
auth.service.connected = true;
commandInfo = Cli.getCommandInfo(command);
});

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

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

after(() => {
sinonUtil.restore([
auth.restoreAuth,
telemetry.trackEvent,
pid.getProcessName,
session.getId
]);
auth.service.connected = false;
auth.service.accessTokens = {};
});

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

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

it('fails validation if id is not a valid GUID', async () => {
const actual = await command.validate({ options: { id: 'invalid' } }, commandInfo);
assert.notStrictEqual(actual, true);
});

it('passes validation if a correct id is entered and includeResults is specified', async () => {
const actual = await command.validate({ options: { id: threatAssessmentId, includeResults: true } }, commandInfo);
assert.strictEqual(actual, true);
});

it('retrieves threat assessment by specified id', async () => {
sinon.stub(request, 'get').callsFake(async (opts) => {
if (opts.url === `https://graph.microsoft.com/v1.0/informationProtection/threatAssessmentRequests/${threatAssessmentId}`) {
return threatAssessmentGetResponse;
}

throw 'Invalid request';
});

await command.action(logger, { options: { id: threatAssessmentId, verbose: true } });
assert(loggerLogSpy.calledWith(threatAssessmentGetResponse));
});

it('retrieves threat assessment by specified id including results', async () => {
sinon.stub(request, 'get').callsFake(async (opts) => {
if (opts.url === `https://graph.microsoft.com/v1.0/informationProtection/threatAssessmentRequests/${threatAssessmentId}?$expand=results`) {
return threatAssessmentGetResponseIncludingResults;
}

throw 'Invalid request';
});

await command.action(logger, { options: { id: threatAssessmentId, includeResults: true, verbose: true } });
assert(loggerLogSpy.calledWith(threatAssessmentGetResponseIncludingResults));
});

it('handles error when threat assessment by specified id is not found', async () => {
const error = {
'error': {
'code': 'ResourceNotFound',
'message': 'The requested resource does not exist.',
'innerError': {
'date': '2023-02-25T16:13:25',
'request-id': 'a9e23bc8-0845-4eef-8ba1-e031b098c955',
'client-request-id': 'a9e23bc8-0845-4eef-8ba1-e031b098c955'
}
}
};
sinon.stub(request, 'get').callsFake(async (opts) => {
if (opts.url === `https://graph.microsoft.com/v1.0/informationProtection/threatAssessmentRequests/${threatAssessmentId}`) {
throw error;
}

throw 'Invalid request';
});

await assert.rejects(command.action(logger, { options: { id: threatAssessmentId } }), new CommandError(error.error.message));
});
});

0 comments on commit c6a243c

Please sign in to comment.