Skip to content

Commit 03a3814

Browse files
authored
Merge branch 'master' into iss176
2 parents 077dea1 + 1be5908 commit 03a3814

25 files changed

+714
-130
lines changed

.github/workflows/publish.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ jobs:
1212
- name: Set up Python
1313
uses: actions/setup-python@v1
1414
with:
15-
python-version: '3.x'
15+
python-version: '3.8'
1616
- name: Install dependencies
1717
run: |
1818
python -m pip install --upgrade pip
@@ -25,7 +25,7 @@ jobs:
2525
src_file=( ./dist/*.tar.gz )
2626
wheel_file=( ./dist/*.whl )
2727
echo "RELEASE_ID=$(jq --raw-output '.release.id' $GITHUB_EVENT_PATH)" >> $GITHUB_ENV
28-
echo "SOURCE_DIST_FILE=$(jq --raw-output '.release.id' $GITHUB_EVENT_PATH)" >> $GITHUB_ENV
28+
echo "SOURCE_DIST_FILE=$(basename $src_file)" >> $GITHUB_ENV
2929
echo "WHEEL_FILE=$(basename $wheel_file)" >> $GITHUB_ENV
3030
- name: Set Upload Url
3131
run: |

CHANGELOG.md

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,20 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
88
The intended audience of this file is for py42 consumers -- as such, changes that don't affect
99
how a consumer would use the library (e.g. adding unit tests, updating documentation, etc) are not captured here.
1010

11-
## Unreleased
11+
# Unreleased
12+
13+
# Added
14+
15+
- `code42 departing-employee list` command.
16+
17+
- `code42 high-risk-employee list` command.
18+
19+
### Changed
20+
21+
- The error text when removing an employee from a detection list now references the employee
22+
by ID rather the username.
23+
24+
## 1.1.0 - 2020-12-18
1225

1326
### Fixed
1427

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ code42 security-data search -b 10d -e 12h
117117

118118
Begin date will be ignored if provided on subsequent queries using `-c/--use-checkpoint`.
119119

120-
Use different format with `-f`:
120+
Use other formats with `-f`:
121121

122122
```bash
123123
code42 security-data search -b 2020-02-02 -f CEF

docs/commands.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
* [Profile](commands/profile.rst)
44
* [Security Data](commands/securitydata.rst)
5+
* [Audit Logs](commands/auditlogs.rst)
56
* [Alerts](commands/alerts.rst)
67
* [Alert Rules](commands/alertrules.rst)
78
* [Departing Employee](commands/departingemployee.rst)

docs/commands/auditlogs.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
.. click:: code42cli.cmds.auditlogs:audit_logs
2+
:prog: auditlogs
3+
:show-nested:

integration/test_alert_rules.py

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
import pytest
2+
from integration import run_command
3+
4+
ALERT_RULES_COMMAND = "code42 alert-rules"
5+
6+
7+
@pytest.mark.integration
8+
@pytest.mark.parametrize(
9+
"command",
10+
[
11+
"{} list".format(ALERT_RULES_COMMAND),
12+
"{} show test-rule-id".format(ALERT_RULES_COMMAND),
13+
"{} list -f CSV".format(ALERT_RULES_COMMAND),
14+
"{} list -f TABLE".format(ALERT_RULES_COMMAND),
15+
"{} list -f RAW-JSON".format(ALERT_RULES_COMMAND),
16+
"{} list -f JSON".format(ALERT_RULES_COMMAND),
17+
"{} list --format CSV".format(ALERT_RULES_COMMAND),
18+
"{} list --format TABLE".format(ALERT_RULES_COMMAND),
19+
"{} list --format JSON".format(ALERT_RULES_COMMAND),
20+
"{} list --format RAW-JSON".format(ALERT_RULES_COMMAND),
21+
],
22+
)
23+
def test_alert_rules_command_returns_success_return_code(command):
24+
return_code, response = run_command(command)
25+
assert return_code == 0
26+
27+
28+
@pytest.mark.parametrize(
29+
"command, error_msg",
30+
[
31+
(
32+
"{} add-user --rule-id test-rule-id".format(ALERT_RULES_COMMAND),
33+
"Missing option '-u' / '--username'.",
34+
),
35+
(
36+
"{} remove-user --rule-id test-rule-id".format(ALERT_RULES_COMMAND),
37+
"Missing option '-u' / '--username'.",
38+
),
39+
("{} add-user".format(ALERT_RULES_COMMAND), "Missing option '--rule-id'."),
40+
("{} remove-user".format(ALERT_RULES_COMMAND), "Missing option '--rule-id'."),
41+
("{} show".format(ALERT_RULES_COMMAND), "Missing argument 'RULE_ID'."),
42+
(
43+
"{} bulk add".format(ALERT_RULES_COMMAND),
44+
"Error: Missing argument 'CSV_FILE'.",
45+
),
46+
(
47+
"{} bulk remove".format(ALERT_RULES_COMMAND),
48+
"Error: Missing argument 'CSV_FILE'.",
49+
),
50+
],
51+
)
52+
def test_alert_rules_command_returns_error_exit_status_when_missing_required_parameters(
53+
command, error_msg
54+
):
55+
return_code, response = run_command(command)
56+
assert return_code == 2
57+
assert error_msg in "".join(response)

integration/test_alerts.py

Lines changed: 36 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -11,21 +11,48 @@
1111
end_date_str = end_date.strftime("%Y-%m-%d")
1212

1313
ALERT_COMMAND = "code42 alerts search -b {} -e {}".format(begin_date_str, end_date_str)
14+
ADVANCED_QUERY = """{"groupClause":"AND", "groups":[{"filterClause":"AND",
15+
"filters":[{"operator":"ON_OR_AFTER", "term":"eventTimestamp", "value":"2020-09-13T00:00:00.000Z"},
16+
{"operator":"ON_OR_BEFORE", "term":"eventTimestamp", "value":"2020-12-07T13:20:15.195Z"}]}],
17+
"srtDir":"asc", "srtKey":"eventId", "pgNum":1, "pgSize":10000}
18+
"""
19+
ALERT_ADVANCED_QUERY_COMMAND = "code42 alerts search --advanced-query '{}'".format(
20+
ADVANCED_QUERY
21+
)
1422

1523

24+
@pytest.mark.integration
1625
@pytest.mark.parametrize(
1726
"command",
1827
[
19-
("{}".format(ALERT_COMMAND)),
20-
("{} --state OPEN".format(ALERT_COMMAND)),
21-
("{} --state RESOLVED".format(ALERT_COMMAND)),
22-
("{} --actor [email protected]".format(ALERT_COMMAND)),
23-
("{} --rule-name 'File Upload Alert'".format(ALERT_COMMAND)),
24-
("{} --rule-id 962a6a1c-54f6-4477-90bd-a08cc74cbf71".format(ALERT_COMMAND)),
25-
("{} --rule-type FedEndpointExfiltration".format(ALERT_COMMAND)),
26-
("{} --description 'Alert on any file upload'".format(ALERT_COMMAND)),
28+
ALERT_COMMAND,
29+
"{} --state OPEN".format(ALERT_COMMAND),
30+
"{} --state RESOLVED".format(ALERT_COMMAND),
31+
"{} --actor [email protected]".format(ALERT_COMMAND),
32+
"{} --rule-name 'File Upload Alert'".format(ALERT_COMMAND),
33+
"{} --rule-id 962a6a1c-54f6-4477-90bd-a08cc74cbf71".format(ALERT_COMMAND),
34+
"{} --rule-type FedEndpointExfiltration".format(ALERT_COMMAND),
35+
"{} --description 'Alert on any file upload'".format(ALERT_COMMAND),
36+
"{} --exclude-rule-type 'FedEndpointExfiltration'".format(ALERT_COMMAND),
37+
"{} --exclude-rule-id '962a6a1c-54f6-4477-90bd-a08cc74cbf71'".format(
38+
ALERT_COMMAND
39+
),
40+
"{} --exclude-rule-name 'File Upload Alert'".format(ALERT_COMMAND),
41+
"{} --exclude-actor-contains '[email protected]'".format(ALERT_COMMAND),
42+
"{} --exclude-actor '[email protected]'".format(ALERT_COMMAND),
43+
"{} --actor-contains '[email protected]'".format(ALERT_COMMAND),
44+
ALERT_ADVANCED_QUERY_COMMAND,
2745
],
2846
)
29-
def test_alert_returns_success_return_code(command):
47+
def test_alert_command_returns_success_return_code(command):
3048
return_code, response = run_command(command)
3149
assert return_code == 0
50+
51+
52+
@pytest.mark.parametrize(
53+
"command", ["{} --advanced-query '{}'".format(ALERT_COMMAND, ADVANCED_QUERY)]
54+
)
55+
def test_begin_cant_be_used_with_advanced_query(command):
56+
return_code, response = run_command(command)
57+
assert return_code == 2
58+
assert "--begin can't be used with: --advanced-query" in response[0]

integration/test_auditlogs.py

Lines changed: 35 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,44 @@
44
import pytest
55
from integration import run_command
66

7-
BASE_COMMAND = "code42 audit-logs search -b"
7+
SEARCH_COMMAND = "code42 audit-logs search"
8+
BASE_COMMAND = "{} -b".format(SEARCH_COMMAND)
89
begin_date = datetime.utcnow() - timedelta(days=-10)
910
begin_date_str = begin_date.strftime("%Y-%m-%d %H:%M:%S")
11+
end_date = datetime.utcnow() - timedelta(days=10)
12+
end_date_str = end_date.strftime("%Y-%m-%d %H:%M:%S")
1013

1114

12-
@pytest.mark.parametrize("command", [("{} '{}'".format(BASE_COMMAND, begin_date_str))])
13-
def test_auditlogs_search(command):
15+
@pytest.mark.integration
16+
@pytest.mark.parametrize(
17+
"command",
18+
[
19+
("{} '{}'".format(BASE_COMMAND, begin_date_str)),
20+
("{} '{}' -e '{}'".format(BASE_COMMAND, begin_date_str, end_date_str)),
21+
("{} '{}' --end '{}'".format(BASE_COMMAND, begin_date_str, end_date_str)),
22+
("{} '{}' --event-type '{}'".format(BASE_COMMAND, begin_date_str, "test")),
23+
("{} '{}' --username '{}'".format(BASE_COMMAND, begin_date_str, "test")),
24+
("{} '{}' --user-id '{}'".format(BASE_COMMAND, begin_date_str, "123")),
25+
("{} '{}' --user-ip '{}'".format(BASE_COMMAND, begin_date_str, "0.0.0.0")),
26+
("{} '{}' --affected-user-id '{}'".format(BASE_COMMAND, begin_date_str, "123")),
27+
(
28+
"{} '{}' --affected-username '{}'".format(
29+
BASE_COMMAND, begin_date_str, "test"
30+
)
31+
),
32+
("{} '{}' -f {}".format(BASE_COMMAND, begin_date_str, "CSV")),
33+
("{} '{}' -f '{}'".format(BASE_COMMAND, begin_date_str, "TABLE")),
34+
("{} '{}' -f '{}'".format(BASE_COMMAND, begin_date_str, "JSON")),
35+
("{} '{}' -f '{}'".format(BASE_COMMAND, begin_date_str, "RAW-JSON")),
36+
("{} '{}' --format {}".format(BASE_COMMAND, begin_date_str, "CSV")),
37+
("{} '{}' --format '{}'".format(BASE_COMMAND, begin_date_str, "TABLE")),
38+
("{} '{}' --format '{}'".format(BASE_COMMAND, begin_date_str, "JSON")),
39+
("{} '{}' --format '{}'".format(BASE_COMMAND, begin_date_str, "RAW-JSON")),
40+
("{} --begin '{}'".format(SEARCH_COMMAND, begin_date_str)),
41+
("{} '{}' -d".format(BASE_COMMAND, begin_date_str)),
42+
("{} '{}' --debug".format(BASE_COMMAND, begin_date_str)),
43+
],
44+
)
45+
def test_auditlogs_search_command_returns_success_return_code(command):
1446
return_code, response = run_command(command)
1547
assert return_code == 0
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import pytest
2+
from integration import run_command
3+
4+
DEPARTING_EMPLOYEE_COMMAND = "code42 departing-employee"
5+
6+
7+
@pytest.mark.parametrize(
8+
"command, error_msg",
9+
[
10+
("{} add".format(DEPARTING_EMPLOYEE_COMMAND), "Missing argument 'USERNAME'."),
11+
(
12+
"{} remove".format(DEPARTING_EMPLOYEE_COMMAND),
13+
"Missing argument 'USERNAME'.",
14+
),
15+
(
16+
"{} bulk add".format(DEPARTING_EMPLOYEE_COMMAND),
17+
"Missing argument 'CSV_FILE'.",
18+
),
19+
(
20+
"{} bulk remove".format(DEPARTING_EMPLOYEE_COMMAND),
21+
"Missing argument 'FILE'.",
22+
),
23+
],
24+
)
25+
def test_departing_employee_command_returns_error_exit_status_when_missing_required_parameters(
26+
command, error_msg
27+
):
28+
return_code, response = run_command(command)
29+
assert return_code == 2
30+
assert error_msg in "".join(response)
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import pytest
2+
from integration import run_command
3+
4+
HR_EMPLOYEE_COMMAND = "code42 high-risk-employee"
5+
6+
7+
@pytest.mark.parametrize(
8+
"command, error_msg",
9+
[
10+
("{} add".format(HR_EMPLOYEE_COMMAND), "Missing argument 'USERNAME'."),
11+
("{} remove".format(HR_EMPLOYEE_COMMAND), "Missing argument 'USERNAME'."),
12+
("{} bulk add".format(HR_EMPLOYEE_COMMAND), "Missing argument 'CSV_FILE'."),
13+
("{} bulk remove".format(HR_EMPLOYEE_COMMAND), "Missing argument 'FILE'."),
14+
(
15+
"{} bulk add-risk-tags".format(HR_EMPLOYEE_COMMAND),
16+
"Missing argument 'CSV_FILE'.",
17+
),
18+
(
19+
"{} bulk remove-risk-tags".format(HR_EMPLOYEE_COMMAND),
20+
"Missing argument 'CSV_FILE'.",
21+
),
22+
],
23+
)
24+
def test_hr_employee_command_returns_error_exit_status_when_missing_required_parameters(
25+
command, error_msg
26+
):
27+
return_code, response = run_command(command)
28+
assert return_code == 2
29+
assert error_msg in "".join(response)

integration/test_legal_hold.py

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
import pytest
2+
from integration import run_command
3+
4+
LEGAL_HOLD_COMMAND = "code42 legal-hold"
5+
6+
7+
@pytest.mark.integration
8+
@pytest.mark.parametrize(
9+
"command",
10+
[
11+
"{} list".format(LEGAL_HOLD_COMMAND),
12+
"{} show 984140047896012577".format(LEGAL_HOLD_COMMAND),
13+
"{} list -f CSV".format(LEGAL_HOLD_COMMAND),
14+
"{} list -f TABLE".format(LEGAL_HOLD_COMMAND),
15+
"{} list -f RAW-JSON".format(LEGAL_HOLD_COMMAND),
16+
"{} list -f JSON".format(LEGAL_HOLD_COMMAND),
17+
"{} list --format CSV".format(LEGAL_HOLD_COMMAND),
18+
"{} list --format TABLE".format(LEGAL_HOLD_COMMAND),
19+
"{} list --format JSON".format(LEGAL_HOLD_COMMAND),
20+
"{} list --format RAW-JSON".format(LEGAL_HOLD_COMMAND),
21+
],
22+
)
23+
def test_alert_rules_command_returns_success_return_code(command):
24+
return_code, response = run_command(command)
25+
assert return_code == 0
26+
27+
28+
@pytest.mark.parametrize(
29+
"command, error_msg",
30+
[
31+
(
32+
"{} add-user --matter-id test-matter-id".format(LEGAL_HOLD_COMMAND),
33+
"Missing option '-u' / '--username'.",
34+
),
35+
(
36+
"{} remove-user --matter-id test-matter-id".format(LEGAL_HOLD_COMMAND),
37+
"Missing option '-u' / '--username'.",
38+
),
39+
(
40+
"{} add-user".format(LEGAL_HOLD_COMMAND),
41+
"Missing option '-m' / '--matter-id'.",
42+
),
43+
(
44+
"{} remove-user".format(LEGAL_HOLD_COMMAND),
45+
"Missing option '-m' / '--matter-id'.",
46+
),
47+
("{} show".format(LEGAL_HOLD_COMMAND), "Missing argument 'MATTER_ID'."),
48+
(
49+
"{} bulk add".format(LEGAL_HOLD_COMMAND),
50+
"Error: Missing argument 'CSV_FILE'.",
51+
),
52+
(
53+
"{} bulk remove".format(LEGAL_HOLD_COMMAND),
54+
"Error: Missing argument 'CSV_FILE'.",
55+
),
56+
],
57+
)
58+
def test_alert_rules_command_returns_error_exit_status_when_missing_required_parameters(
59+
command, error_msg
60+
):
61+
return_code, response = run_command(command)
62+
assert return_code == 2
63+
assert error_msg in "".join(response)

run_integration.py

Lines changed: 0 additions & 13 deletions
This file was deleted.

src/code42cli/__version__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
__version__ = "1.0.0"
1+
__version__ = "1.1.0"

src/code42cli/click_ext/groups.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
from py42.exceptions import Py42InvalidRuleOperationError
99
from py42.exceptions import Py42LegalHoldNotFoundOrPermissionDeniedError
1010
from py42.exceptions import Py42UserAlreadyAddedError
11+
from py42.exceptions import Py42UserNotOnListError
1112

1213
from code42cli.errors import Code42CLIError
1314
from code42cli.errors import LoggedCLIError
@@ -53,6 +54,7 @@ def invoke(self, ctx):
5354
except (
5455
UserDoesNotExistError,
5556
Py42UserAlreadyAddedError,
57+
Py42UserNotOnListError,
5658
Py42InvalidRuleOperationError,
5759
Py42LegalHoldNotFoundOrPermissionDeniedError,
5860
) as err:

0 commit comments

Comments
 (0)