Skip to content

Commit ac7ead1

Browse files
Chronicle Teamcopybara-github
authored andcommitted
Adding v2/archive_rule.py and v2/unarchive_rule.py Python samples
PiperOrigin-RevId: 372721574
1 parent 65de7d9 commit ac7ead1

4 files changed

Lines changed: 239 additions & 0 deletions

File tree

detect/v2/archive_rule.py

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
#!/usr/bin/env python3
2+
3+
# Copyright 2021 Google LLC
4+
#
5+
# Licensed under the Apache License, Version 2.0 (the "License");
6+
# you may not use this file except in compliance with the License.
7+
# You may obtain a copy of the License at
8+
#
9+
# http://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# Unless required by applicable law or agreed to in writing, software
12+
# distributed under the License is distributed on an "AS IS" BASIS,
13+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
# See the License for the specific language governing permissions and
15+
# limitations under the License.
16+
#
17+
"""Executable and reusable sample for archiving a detection rule."""
18+
19+
import argparse
20+
21+
from google.auth.transport import requests
22+
23+
from common import chronicle_auth
24+
25+
CHRONICLE_API_BASE_URL = "https://backstory.googleapis.com"
26+
27+
28+
def archive_rule(http_session: requests.AuthorizedSession, version_id: str):
29+
"""Archives a detection rule.
30+
31+
Archiving a rule will fail if:
32+
- The provided version is not the latest rule version
33+
- The rule is enabled as live
34+
- The rule has retrohunts in progress
35+
36+
If alerting is enabled for a rule, archiving the rule will automatically
37+
disable alerting for the rule.
38+
39+
Args:
40+
http_session: Authorized session for HTTP requests.
41+
version_id: Unique ID of the detection rule to archive ("ru_<UUID>" or
42+
"ru_<UUID>@v_<seconds>_<nanoseconds>"). If a version suffix isn't
43+
specified we use the rule's latest version.
44+
45+
Raises:
46+
requests.exceptions.HTTPError: HTTP request resulted in an error
47+
(response.status_code >= 400).
48+
"""
49+
url = f"{CHRONICLE_API_BASE_URL}/v2/detect/rules/{version_id}:archive"
50+
51+
response = http_session.request("POST", url)
52+
# Expected server response:
53+
# {}
54+
55+
if response.status_code >= 400:
56+
print(response.text)
57+
response.raise_for_status()
58+
59+
60+
if __name__ == "__main__":
61+
parser = argparse.ArgumentParser()
62+
chronicle_auth.add_argument_credentials_file(parser)
63+
parser.add_argument(
64+
"-vi",
65+
"--version_id",
66+
type=str,
67+
required=True,
68+
help="version ID ('ru_<UUID>[@v_<seconds>_<nanoseconds>]')")
69+
70+
args = parser.parse_args()
71+
session = chronicle_auth.init_session(
72+
chronicle_auth.init_credentials(args.credentials_file))
73+
archive_rule(session, args.version_id)

detect/v2/archive_rule_test.py

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
# Copyright 2021 Google LLC
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
#
15+
"""Unit tests for the "archive_rule" module."""
16+
17+
import unittest
18+
from unittest import mock
19+
20+
from google.auth.transport import requests
21+
from . import archive_rule
22+
23+
24+
class ArchiveRuleTest(unittest.TestCase):
25+
26+
@mock.patch.object(requests, "AuthorizedSession", autospec=True)
27+
@mock.patch.object(requests.requests, "Response", autospec=True)
28+
def test_http_error(self, mock_response, mock_session):
29+
mock_session.request.return_value = mock_response
30+
type(mock_response).status_code = mock.PropertyMock(return_value=400)
31+
mock_response.raise_for_status.side_effect = (
32+
requests.requests.exceptions.HTTPError())
33+
34+
with self.assertRaises(requests.requests.exceptions.HTTPError):
35+
archive_rule.archive_rule(mock_session,
36+
"ru_12345678-1234-1234-1234-1234567890ab")
37+
38+
@mock.patch.object(requests, "AuthorizedSession", autospec=True)
39+
@mock.patch.object(requests.requests, "Response", autospec=True)
40+
def test_happy_path(self, mock_response, mock_session):
41+
mock_session.request.return_value = mock_response
42+
type(mock_response).status_code = mock.PropertyMock(return_value=200)
43+
44+
archive_rule.archive_rule(mock_session,
45+
"ru_12345678-1234-1234-1234-1234567890ab")
46+
47+
48+
if __name__ == "__main__":
49+
unittest.main()

detect/v2/unarchive_rule.py

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
#!/usr/bin/env python3
2+
3+
# Copyright 2021 Google LLC
4+
#
5+
# Licensed under the Apache License, Version 2.0 (the "License");
6+
# you may not use this file except in compliance with the License.
7+
# You may obtain a copy of the License at
8+
#
9+
# http://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# Unless required by applicable law or agreed to in writing, software
12+
# distributed under the License is distributed on an "AS IS" BASIS,
13+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
# See the License for the specific language governing permissions and
15+
# limitations under the License.
16+
#
17+
"""Executable and reusable sample for unarchiving a detection rule."""
18+
19+
import argparse
20+
21+
from google.auth.transport import requests
22+
23+
from common import chronicle_auth
24+
25+
CHRONICLE_API_BASE_URL = "https://backstory.googleapis.com"
26+
27+
28+
def unarchive_rule(http_session: requests.AuthorizedSession, version_id: str):
29+
"""Unarchives a detection rule.
30+
31+
Unarchiving a rule will fail if the provided version is not the latest rule
32+
version.
33+
34+
Args:
35+
http_session: Authorized session for HTTP requests.
36+
version_id: Unique ID of the detection rule to unarchive ("ru_<UUID>" or
37+
"ru_<UUID>@v_<seconds>_<nanoseconds>"). If a version suffix isn't
38+
specified we use the rule's latest version.
39+
40+
Raises:
41+
requests.exceptions.HTTPError: HTTP request resulted in an error
42+
(response.status_code >= 400).
43+
"""
44+
url = f"{CHRONICLE_API_BASE_URL}/v2/detect/rules/{version_id}:unarchive"
45+
46+
response = http_session.request("POST", url)
47+
# Expected server response:
48+
# {}
49+
50+
if response.status_code >= 400:
51+
print(response.text)
52+
response.raise_for_status()
53+
54+
55+
if __name__ == "__main__":
56+
parser = argparse.ArgumentParser()
57+
chronicle_auth.add_argument_credentials_file(parser)
58+
parser.add_argument(
59+
"-vi",
60+
"--version_id",
61+
type=str,
62+
required=True,
63+
help="version ID ('ru_<UUID>[@v_<seconds>_<nanoseconds>]')")
64+
65+
args = parser.parse_args()
66+
session = chronicle_auth.init_session(
67+
chronicle_auth.init_credentials(args.credentials_file))
68+
unarchive_rule(session, args.version_id)

detect/v2/unarchive_rule_test.py

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
# Copyright 2021 Google LLC
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
#
15+
"""Unit tests for the "archive_rule" module."""
16+
17+
import unittest
18+
from unittest import mock
19+
20+
from google.auth.transport import requests
21+
from . import unarchive_rule
22+
23+
24+
class ArchiveRuleTest(unittest.TestCase):
25+
26+
@mock.patch.object(requests, "AuthorizedSession", autospec=True)
27+
@mock.patch.object(requests.requests, "Response", autospec=True)
28+
def test_http_error(self, mock_response, mock_session):
29+
mock_session.request.return_value = mock_response
30+
type(mock_response).status_code = mock.PropertyMock(return_value=400)
31+
mock_response.raise_for_status.side_effect = (
32+
requests.requests.exceptions.HTTPError())
33+
34+
with self.assertRaises(requests.requests.exceptions.HTTPError):
35+
unarchive_rule.unarchive_rule(mock_session,
36+
"ru_12345678-1234-1234-1234-1234567890ab")
37+
38+
@mock.patch.object(requests, "AuthorizedSession", autospec=True)
39+
@mock.patch.object(requests.requests, "Response", autospec=True)
40+
def test_happy_path(self, mock_response, mock_session):
41+
mock_session.request.return_value = mock_response
42+
type(mock_response).status_code = mock.PropertyMock(return_value=200)
43+
44+
unarchive_rule.unarchive_rule(mock_session,
45+
"ru_12345678-1234-1234-1234-1234567890ab")
46+
47+
48+
if __name__ == "__main__":
49+
unittest.main()

0 commit comments

Comments
 (0)