diff --git a/base64decode.py b/base64decode.py index d951f78..0740a6c 100644 --- a/base64decode.py +++ b/base64decode.py @@ -1,4 +1,127 @@ +# Save this as create_company_credentials_xlsx.py and run with: python create_company_credentials_xlsx.py +# Requires: openpyxl, pandas +# Install: pip install openpyxl pandas + +import io import base64 -encoded = 'YmFzZTY0IGVuY29kZWQgc3RyaW5n' -data = base64.b64decode(encoded) -print data +from datetime import datetime +import pandas as pd +from openpyxl import load_workbook, Workbook +from openpyxl.worksheet.table import Table, TableStyleInfo +from openpyxl.formatting.rule import FormulaRule +from openpyxl.styles import PatternFill, Font + +# User / workbook metadata +AUTHOR = "Amir Sadiq" +DEPARTMENT = "Data/Analytics" +FILENAME = "company_credentials.xlsx" + +# Data for sheets +company_credentials_csv = """Account Name,Environment,Service Type,Owner,Created Date,Last Rotated,Rotation Frequency (Days),Storage Location,Access Level,Notes +billing.prod.api-key,Production,API Key,Billing Team,2025-10-01,2025-11-01,30,/vault/billing/prod/api,Admin,Critical — rotate monthly +crm.staging.password,Staging,Password,Sales Ops,2025-09-12,2025-10-15,90,/vault/crm/staging/auth,Write,Partner staging credentials +analytics.dev.ssh-key,Development,SSH Key,Data Engineering,2025-08-05,2025-08-30,180,/vault/analytics/dev/ssh,Read,Used for ETL job testing only +""" +rotation_schedule_csv = """Credential Name,Owner,Rotation Frequency (Days),Last Rotated,Next Rotation Due,Status +billing.prod.api-key,Billing Team,30,2025-11-01,2025-12-01,Scheduled +crm.staging.password,Sales Ops,90,2025-10-15,2026-01-13,Pending +analytics.dev.ssh-key,Data Engineering,180,2025-08-30,2026-02-26,Active +""" +access_requests_csv = """Requestor,Request Date,Resource,Environment,Access Level,Justification,Duration,Approver,Status +Amir Sadiq,2025-12-11,billing.prod.api-key,Production,Write,Monthly reporting run,Temporary (3 days),IT Security Manager,Approved +John Doe,2025-12-08,crm.staging.password,Staging,Admin,QA testing,Permanent,Sales Ops Lead,Pending +""" + +# Read CSVs into DataFrames +df_company = pd.read_csv(io.StringIO(company_credentials_csv), parse_dates=["Created Date","Last Rotated"], dayfirst=False) +df_rotation = pd.read_csv(io.StringIO(rotation_schedule_csv), parse_dates=["Last Rotated","Next Rotation Due"]) +df_access = pd.read_csv(io.StringIO(access_requests_csv), parse_dates=["Request Date"]) + +# Create workbook and add sheets +wb = Workbook() +# Remove default sheet +default = wb.active +wb.remove(default) + +def add_sheet_from_df(wb, title, df): + ws = wb.create_sheet(title=title) + # Write headers + ws.append(list(df.columns)) + # Write rows + for r in df.itertuples(index=False, name=None): + # Ensure datetimes remain datetimes + row = [] + for val in r: + row.append(val) + ws.append(row) + # Freeze top row + ws.freeze_panes = "A2" + # Create Table object for formatting (auto-detect range) + max_row = ws.max_row + max_col = ws.max_column + table_ref = f"A1:{chr(64+max_col)}{max_row}" + table = Table(displayName=title.replace(" ", "_")[:24], ref=table_ref) + style = TableStyleInfo(name="TableStyleMedium9", showFirstColumn=False, + showLastColumn=False, showRowStripes=True, showColumnStripes=False) + table.tableStyleInfo = style + ws.add_table(table) + # Apply autofilter (tables already create filter) + return ws + +ws1 = add_sheet_from_df(wb, "Company Credentials", df_company) +ws2 = add_sheet_from_df(wb, "Rotation Schedule", df_rotation) +ws3 = add_sheet_from_df(wb, "Access Requests", df_access) + +# Conditional formatting on Rotation Schedule -> Next Rotation Due column +# Find column letter for "Next Rotation Due" +def find_col_letter(ws, col_name): + for cell in ws[1]: + if str(cell.value).strip() == col_name: + return cell.column_letter + return None + +col_letter = find_col_letter(ws2, "Next Rotation Due") +if col_letter: + start_row = 2 + end_row = ws2.max_row + rng = f"{col_letter}{start_row}:{col_letter}{end_row}" + + # Overdue: dark red fill, white font + overdue_fill = PatternFill(start_color="8B0000", end_color="8B0000", fill_type="solid") + overdue_font = Font(color="FFFFFF", bold=True) + overdue_rule = FormulaRule(formula=[f"${col_letter}{start_row}=0)"], fill=red_fill) + + # Within 30 days: orange + orange_fill = PatternFill(start_color="FFD966", end_color="FFD966", fill_type="solid") + orange_rule = FormulaRule(formula=[f"AND(ISNUMBER(${col_letter}{start_row}), ${col_letter}{start_row}-TODAY()<=30, ${col_letter}{start_row}-TODAY()>7)"], fill=orange_fill) + + # Apply rules (openpyxl applies rule to range by setting rule.formula and ws.conditional_formatting.add) + ws2.conditional_formatting.add(rng, overdue_rule) + ws2.conditional_formatting.add(rng, red_rule) + ws2.conditional_formatting.add(rng, orange_rule) + +# Set workbook core properties (metadata) +from openpyxl.packaging.core import CoreProperties +wb.properties.creator = AUTHOR +wb.properties.lastModifiedBy = AUTHOR +wb.properties.title = "Company Credentials" +wb.properties.subject = "Credentials inventory and rotation" +wb.properties.description = f"Generated for {AUTHOR} — Department: {DEPARTMENT}" +wb.properties.created = datetime.now() + +# Save to file +wb.save(FILENAME) + +# Also output base64 of the saved file to stdout for easy download/transfer +with open(FILENAME, "rb") as f: + data = f.read() +b64 = base64.b64encode(data).decode("utf-8") + +# Print instructions and base64 +print(f"Saved {FILENAME} to current directory.") +print("Base64 output below (copy the entire block and decode to get the .xlsx):\n") +print(b64)