Skip to content

Commit e01dfbc

Browse files
authored
Merge branch 'stable' into monthlyupdate
2 parents 38ce774 + d15f4bd commit e01dfbc

44 files changed

Lines changed: 2491 additions & 2114 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.flake8

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
[flake8]
22
# These rules are ignored
33
# - E501 line too long
4-
ignore = E501
5-
max-line-length = 120
4+
# - E203 whitespace before ':' (conflicts with Black formatting)
5+
# - D100-D400 docstring style warnings (legacy code, will be addressed separately)
6+
extend-ignore = E501, E203, D
7+
max-line-length = 160

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,3 +17,5 @@ kubectl.exe
1717
/build
1818
/.vscode
1919
/site
20+
/.bob/.bob-errors
21+
/.bob/notes

.pre-commit-config.yaml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
default_language_version:
22
python: python
33
repos:
4-
- repo: https://github.com/hhatto/autopep8
5-
rev: v2.3.2
4+
- repo: https://github.com/psf/black
5+
rev: 26.5.1
66
hooks:
7-
- id: autopep8
7+
- id: black
88
- repo: https://github.com/PyCQA/flake8
99
rev: 7.3.0
1010
hooks:

.secrets.baseline

Lines changed: 41 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
"files": "^.secrets.baseline$",
44
"lines": null
55
},
6-
"generated_at": "2026-05-21T00:57:00Z",
6+
"generated_at": "2026-06-17T12:31:04Z",
77
"plugins_used": [
88
{
99
"name": "AWSKeyDetector"
@@ -87,6 +87,16 @@
8787
"verified_result": null
8888
}
8989
],
90+
"bin/mas-devops-create-initial-users-for-saas": [
91+
{
92+
"hashed_secret": "28ed3a797da3c48c309a4ef792147f3c56cfec40",
93+
"is_secret": false,
94+
"is_verified": false,
95+
"line_number": 116,
96+
"type": "Secret Keyword",
97+
"verified_result": null
98+
}
99+
],
90100
"bin/mas-devops-notify-slack": [
91101
{
92102
"hashed_secret": "053f5ed451647be0bbb6f67b80d6726808cad97e",
@@ -158,7 +168,7 @@
158168
"hashed_secret": "4dfd3a58b4820476afe7efa2e2c52b267eec876a",
159169
"is_secret": false,
160170
"is_verified": false,
161-
"line_number": 753,
171+
"line_number": 688,
162172
"type": "Secret Keyword",
163173
"verified_result": null
164174
}
@@ -168,7 +178,7 @@
168178
"hashed_secret": "a4b48a81cdab1e1a5dd37907d6c85ca1c61ddc7c",
169179
"is_secret": false,
170180
"is_verified": false,
171-
"line_number": 290,
181+
"line_number": 245,
172182
"type": "Secret Keyword",
173183
"verified_result": null
174184
}
@@ -178,15 +188,41 @@
178188
"hashed_secret": "94f5ed592906089c107208b29e178ddf1f9f5143",
179189
"is_secret": false,
180190
"is_verified": false,
181-
"line_number": 42,
191+
"line_number": 40,
182192
"type": "Secret Keyword",
183193
"verified_result": null
184194
},
185195
{
186196
"hashed_secret": "a9410d9785f49750b9f8672794fc288558c1611c",
187197
"is_secret": false,
188198
"is_verified": false,
189-
"line_number": 55,
199+
"line_number": 60,
200+
"type": "Secret Keyword",
201+
"verified_result": null
202+
}
203+
],
204+
"test/src/test_users.py": [
205+
{
206+
"hashed_secret": "74ba31d41223751c75cc0a453dd7df04889bdc72",
207+
"is_secret": false,
208+
"is_verified": false,
209+
"line_number": 143,
210+
"type": "Secret Keyword",
211+
"verified_result": null
212+
},
213+
{
214+
"hashed_secret": "2edced2e2f44a016a5b2e5ce25fe704e62cbb2e7",
215+
"is_secret": false,
216+
"is_verified": false,
217+
"line_number": 150,
218+
"type": "Secret Keyword",
219+
"verified_result": null
220+
},
221+
{
222+
"hashed_secret": "f66f0353de50f6990a5d761b00268056fa80f95f",
223+
"is_secret": false,
224+
"is_verified": false,
225+
"line_number": 1945,
190226
"type": "Secret Keyword",
191227
"verified_result": null
192228
}

README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
mas.devops
22
===============================================================================
3-
[![Code style: PEP8](https://img.shields.io/badge/code%20style-PEP--8-blue.svg)](https://peps.python.org/pep-0008/)
3+
[![Code Style: Black](https://img.shields.io/badge/Code%20Style-Black-000000.svg)](https://github.com/psf/black)
44
[![Flake8: checked](https://img.shields.io/badge/flake8-checked-blueviolet)](https://flake8.pycqa.org/en/latest/)
55
![GitHub Actions Workflow Status](https://img.shields.io/github/actions/workflow/status/ibm-mas/python-devops/python-release.yml)
66
[![PyPI - Version](https://img.shields.io/pypi/v/mas.devops)](https://pypi.org/project/mas-devops)
@@ -31,7 +31,7 @@ installOpenShiftPipelines(dynamicClient)
3131

3232
# Create the pipelines namespace and install the MAS tekton definitions
3333
createNamespace(dynamicClient, pipelinesNamespace)
34-
updateTektonDefinitions(pipelinesNamespace, "/mascli/templates/ibm-mas-tekton.yaml")
34+
updateTektonDefinitions(dynamicClient, pipelinesNamespace, "/mascli/templates/ibm-mas-tekton.yaml")
3535

3636
# Launch the upgrade pipeline and print the URL to view the pipeline run
3737
pipelineURL = launchUpgradePipeline(self.dynamicClient, instanceId)
@@ -73,7 +73,7 @@ mas-devops-create-initial-users-for-saas \
7373
--manage-api-port 8443 \
7474
--coreapi-port 8444 \
7575
--admin-dashboard-port 8445
76-
76+
7777

7878
mas-devops-create-initial-users-for-saas \
7979
--mas-instance-id tgk01 \

bin/mas-devops-apply-preinstall-rbac-for-saas

Lines changed: 42 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -18,51 +18,69 @@ import sys
1818
import argparse
1919
import logging
2020
import urllib3
21+
2122
urllib3.disable_warnings()
2223

2324

2425
if __name__ == "__main__":
25-
parser = argparse.ArgumentParser(description='Apply Pre-Install MAS RBAC')
26-
26+
parser = argparse.ArgumentParser(description="Apply Pre-Install MAS RBAC")
27+
2728
parser.add_argument("--mas-instance-id", required=True, help="MAS Instance ID")
2829
parser.add_argument("--mas-version", required=True, help="MAS Version (e.g., 9.2)")
29-
parser.add_argument("--admin-mode", required=False, default="namespaced",
30-
choices=["cluster", "namespaced", "minimal"],
31-
help="Admin mode: cluster, namespaced, or minimal")
32-
parser.add_argument("--selected-apps", required=False, default="core",
33-
help="Comma-separated list of apps (e.g., core,manage,iot)")
34-
parser.add_argument("--rbac-root-dir", required=False, default="/opt/app-root/rbac",
35-
help="Root directory containing RBAC manifests")
36-
parser.add_argument("--log-level", required=False,
37-
choices=["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"],
38-
default="INFO")
39-
30+
parser.add_argument(
31+
"--admin-mode",
32+
required=False,
33+
default="namespaced",
34+
choices=["cluster", "namespaced", "minimal"],
35+
help="Admin mode: cluster, namespaced, or minimal",
36+
)
37+
parser.add_argument(
38+
"--selected-apps",
39+
required=False,
40+
default="core",
41+
help="Comma-separated list of apps (e.g., core,manage,iot)",
42+
)
43+
parser.add_argument(
44+
"--rbac-root-dir",
45+
required=False,
46+
default="/opt/app-root/rbac",
47+
help="Root directory containing RBAC manifests",
48+
)
49+
parser.add_argument(
50+
"--log-level",
51+
required=False,
52+
choices=["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"],
53+
default="INFO",
54+
)
55+
4056
args = parser.parse_args()
41-
57+
4258
# Setup logging
4359
log_level = getattr(logging, args.log_level)
4460
logger = logging.getLogger()
4561
logger.setLevel(log_level)
46-
62+
4763
ch = logging.StreamHandler()
4864
ch.setLevel(log_level)
4965
chFormatter = logging.Formatter(
5066
"%(asctime)-25s %(name)-50s %(levelname)-8s %(message)s"
5167
)
5268
ch.setFormatter(chFormatter)
5369
logger.addHandler(ch)
54-
70+
5571
mas_instance_id = args.mas_instance_id
5672
mas_version = ".".join(args.mas_version.split(".")[:2])
5773
admin_mode = args.admin_mode
5874
selected_apps_str = args.selected_apps
5975
rbac_root_dir = args.rbac_root_dir
60-
76+
6177
# Parse selected apps
6278
selected_apps = None
6379
if selected_apps_str:
64-
selected_apps = [app.strip() for app in selected_apps_str.split(',') if app.strip()]
65-
80+
selected_apps = [
81+
app.strip() for app in selected_apps_str.split(",") if app.strip()
82+
]
83+
6684
logger.info("Configuration:")
6785
logger.info("--------------")
6886
logger.info(f"mas_instance_id: {mas_instance_id}")
@@ -72,7 +90,7 @@ if __name__ == "__main__":
7290
logger.info(f"rbac_root_dir: {rbac_root_dir}")
7391
logger.info(f"log_level: {log_level}")
7492
logger.info("")
75-
93+
7694
try:
7795
# Try to load in-cluster configuration
7896
config.load_incluster_config()
@@ -81,7 +99,7 @@ if __name__ == "__main__":
8199
# If that fails, fall back to kubeconfig file
82100
config.load_kube_config()
83101
logger.debug("Loaded kubeconfig file")
84-
102+
85103
try:
86104
dynClient = DynamicClient(client.api_client.ApiClient())
87105
applyPreInstallMASRBAC(
@@ -90,12 +108,13 @@ if __name__ == "__main__":
90108
masInstanceId=mas_instance_id,
91109
adminMode=admin_mode,
92110
selectedApps=selected_apps,
93-
rbacRootDir=rbac_root_dir
111+
rbacRootDir=rbac_root_dir,
94112
)
95113
logger.info("Pre-Install MAS RBAC applied successfully")
96114
sys.exit(0)
97115
except Exception as e:
98116
logger.error(f"Error applying Pre-Install MAS RBAC: {e}")
99117
import traceback
118+
100119
traceback.print_exc()
101-
sys.exit(1)
120+
sys.exit(1)

bin/mas-devops-create-initial-users-for-saas

Lines changed: 40 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ from kubernetes.config.config_exception import ConfigException
2121
import argparse
2222
import logging
2323
import urllib3
24+
2425
urllib3.disable_warnings()
2526

2627

@@ -30,7 +31,12 @@ if __name__ == "__main__":
3031
# Primary Options
3132
parser.add_argument("--mas-instance-id", required=True)
3233
parser.add_argument("--mas-workspace-id", required=True)
33-
parser.add_argument("--log-level", required=False, choices=["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"], default="INFO")
34+
parser.add_argument(
35+
"--log-level",
36+
required=False,
37+
choices=["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"],
38+
default="INFO",
39+
)
3440
parser.add_argument("--coreapi-port", required=False, default=443)
3541
parser.add_argument("--admin-dashboard-port", required=False, default=443)
3642
parser.add_argument("--manage-api-port", required=False, default=443)
@@ -86,31 +92,47 @@ if __name__ == "__main__":
8692
config.load_kube_config()
8793
logger.debug("Loaded kubeconfig file")
8894

89-
user_utils = MASUserUtils(mas_instance_id, mas_workspace_id, client.api_client.ApiClient(), mas_version, coreapi_port=coreapi_port, admin_dashboard_port=admin_dashboard_port, manage_api_port=manage_api_port)
95+
user_utils = MASUserUtils(
96+
mas_instance_id,
97+
mas_workspace_id,
98+
client.api_client.ApiClient(),
99+
mas_version,
100+
coreapi_port=coreapi_port,
101+
admin_dashboard_port=admin_dashboard_port,
102+
manage_api_port=manage_api_port,
103+
)
90104

91105
if initial_users_secret_name is not None:
92106

93-
logger.info(f"Loading initial_users configuration from secret {initial_users_secret_name}")
107+
logger.info(
108+
f"Loading initial_users configuration from secret {initial_users_secret_name}"
109+
)
94110

95111
session = boto3.session.Session()
96112
aws_sm_client = session.client(
97-
service_name='secretsmanager',
113+
service_name="secretsmanager",
98114
)
99115
try:
100-
initial_users_secret = aws_sm_client.get_secret_value( # pragma: allowlist secret
101-
SecretId=initial_users_secret_name
116+
initial_users_secret = (
117+
aws_sm_client.get_secret_value( # pragma: allowlist secret
118+
SecretId=initial_users_secret_name
119+
)
102120
)
103121
except ClientError as e:
104-
if e.response['Error']['Code'] == 'ResourceNotFoundException':
105-
logger.info(f"Secret {initial_users_secret_name} was not found, nothing to do, exiting now.")
122+
if e.response["Error"]["Code"] == "ResourceNotFoundException":
123+
logger.info(
124+
f"Secret {initial_users_secret_name} was not found, nothing to do, exiting now."
125+
)
106126
sys.exit(0)
107127

108-
raise Exception(f"Failed to fetch secret {initial_users_secret_name}: {str(e)}")
128+
raise Exception(
129+
f"Failed to fetch secret {initial_users_secret_name}: {str(e)}"
130+
)
109131

110-
secret_json = json.loads(initial_users_secret['SecretString'])
132+
secret_json = json.loads(initial_users_secret["SecretString"])
111133
initial_users = user_utils.parse_initial_users_from_aws_secret_json(secret_json)
112134
elif initial_users_yaml_file is not None:
113-
with open(initial_users_yaml_file, 'r') as file:
135+
with open(initial_users_yaml_file, "r") as file:
114136
initial_users = yaml.safe_load(file)
115137
else:
116138
raise Exception("Something unexpected happened")
@@ -122,7 +144,9 @@ if __name__ == "__main__":
122144
if initial_users_secret_name is not None:
123145
has_updates = False
124146
for completed_user in result["completed"]:
125-
logger.info(f"Removing synced user {completed_user['email']} from {initial_users_secret_name} secret")
147+
logger.info(
148+
f"Removing synced user {completed_user['email']} from {initial_users_secret_name} secret"
149+
)
126150
secret_json.pop(completed_user["email"])
127151
has_updates = True
128152

@@ -131,10 +155,12 @@ if __name__ == "__main__":
131155
try:
132156
aws_sm_client.update_secret( # pragma: allowlist secret
133157
SecretId=initial_users_secret_name,
134-
SecretString=json.dumps(secret_json)
158+
SecretString=json.dumps(secret_json),
135159
)
136160
except ClientError as e:
137-
raise Exception(f"Failed to update secret {initial_users_secret_name}: {str(e)}")
161+
raise Exception(
162+
f"Failed to update secret {initial_users_secret_name}: {str(e)}"
163+
)
138164

139165
if len(result["failed"]) > 0:
140166
failed_user_ids = list(map(lambda u: u["email"], result["failed"]))

0 commit comments

Comments
 (0)