Initial Commit

This commit is contained in:
Mira Kristipati 2025-05-22 15:19:16 -04:00
parent 07de5a2996
commit bcd9706454
30 changed files with 302 additions and 968 deletions

3
.gitignore vendored
View file

@ -1,2 +1 @@
.venv result
.ruff_cache

View file

@ -1,3 +0,0 @@
# Calliope
A monorepo for QoL stuff for Adaptation

17
calliope.nix Normal file
View file

@ -0,0 +1,17 @@
# Consumes user.nix, configuration.nix
{ config, pkgs, lib, ... }:
{ config, pkgs, lib, ...}:
{
imports = [
./configuration.nix
./user.nix
];
calliope = {
hostName = "marcille";
ipv4Address = "172.18.154.50";
cec = "akristip";
username = "mira";
shell = pkgs.xonsh;
#password = "";
}
}

135
configuration.nix Normal file
View file

@ -0,0 +1,135 @@
# Edit this configuration file to define what should be installed on
# your system. Help is available in the configuration.nix(5) man page
# and in the NixOS manual (accessible by running nixos-help).
{ config, pkgs, lib, ... }:
{
# imports =
# [ # Include the results of the hardware scan.
# ./user.nix
# ];
networking.nameservers = [ "64.102.6.247" ];
networking.search = [ "cisco.com" ];
# Bootloader.
boot.loader.systemd-boot.enable = true;
boot.loader.efi.canTouchEfiVariables = true;
nix.package = pkgs.lix;
nix.settings.experimental-features = [ "nix-command" "flakes" ];
# networking.wireless.enable = true; # Enables wireless support via wpa_supplicant.
# Configure network proxy if necessary
# networking.proxy.default = "http://user:password@proxy:port/";
# networking.proxy.noProxy = "127.0.0.1,localhost,internal.domain";
# Set your time zone.
time.timeZone = "America/New_York";
# Select internationalisation properties.
i18n.defaultLocale = "en_US.UTF-8";
i18n.extraLocaleSettings = {
LC_ADDRESS = "en_US.UTF-8";
LC_IDENTIFICATION = "en_US.UTF-8";
LC_MEASUREMENT = "en_US.UTF-8";
LC_MONETARY = "en_US.UTF-8";
LC_NAME = "en_US.UTF-8";
LC_NUMERIC = "en_US.UTF-8";
LC_PAPER = "en_US.UTF-8";
LC_TELEPHONE = "en_US.UTF-8";
LC_TIME = "en_US.UTF-8";
};
# Configure keymap in X11
services.xserver.xkb = {
layout = "us";
variant = "";
};
# Define a user account. Don't forget to set a password with passwd.
users.users.mira = {
isNormalUser = true;
description = "Mira";
extraGroups = [ "networkmanager" "wheel" ];
packages = with pkgs; [];
};
users.users.chris = {
isNormalUser = true;
description = "Chris";
extraGroups = [ "networkmanager" "wheel" ];
packages = with pkgs; [];
};
# Enable automatic login for the user.
services.getty.autologinUser = lib.mkDefault "mira";
# Allow unfree packages
nixpkgs.config.allowUnfree = true;
# List packages installed in system profile. To search, run:
# $ nix search wget
environment.systemPackages = with pkgs; [
# vim # Do not forget to add an editor to edit configuration.nix! The Nano editor is also installed by default.
# wget
lsd
fd
ripgrep
thefuck
nh
hyfetch
fastfetch
uv
edit
];
programs.neovim = {
enable = true;
defaultEditor = true;
};
# Some programs need SUID wrappers, can be configured further or are
# started in user sessions.
# programs.mtr.enable = true;
programs.gnupg.agent = {
enable = true;
enableSSHSupport = true;
};
programs.tmux = {
enable = true;
shortcut = "a";
keyMode = "vi";
};
# TODO: copy git config here
# TODO: configure git-delta
# TODO: set aliases (eg ls to lsd)
# List services that you want to enable:
# Enable the OpenSSH daemon.
services.openssh.enable = true;
# Open ports in the firewall.
# networking.firewall.allowedTCPPorts = [ ... ];
# networking.firewall.allowedUDPPorts = [ ... ];
# Or disable the firewall altogether.
networking.firewall.enable = true;
# This value determines the NixOS release from which the default
# settings for stateful data, like file locations and database versions
# on your system were taken. Its perfectly fine and recommended to leave
# this value at the release version of the first install of this system.
# Before changing this value read the documentation for this option
# (e.g. man configuration.nix or on https://nixos.org/nixos/options.html).
system.stateVersion = "24.11"; # Did you read the comment?
virtualisation.vmware.guest.enable = true;
}

27
flake.lock generated Normal file
View file

@ -0,0 +1,27 @@
{
"nodes": {
"nixpkgs": {
"locked": {
"lastModified": 1747825515,
"narHash": "sha256-BWpMQymVI73QoKZdcVCxUCCK3GNvr/xa2Dc4DM1o2BE=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "cd2812de55cf87df88a9e09bf3be1ce63d50c1a6",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixos-25.05",
"repo": "nixpkgs",
"type": "github"
}
},
"root": {
"inputs": {
"nixpkgs": "nixpkgs"
}
}
},
"root": "root",
"version": 7
}

27
flake.nix Normal file
View file

@ -0,0 +1,27 @@
{
inputs = {
# NOTE: Replace "nixos-23.11" with that which is in system.stateVersion of
# configuration.nix. You can also use latter versions if you wish to
# upgrade.
nixpkgs.url = "github:NixOS/nixpkgs/nixos-25.05";
};
outputs = inputs@{ self, nixpkgs, ... }: {
# NOTE: 'nixos' is the default hostname set by the installer
nixosConfigurations.marcille = nixpkgs.lib.nixosSystem {
# NOTE: Change this to aarch64-linux if you are on ARM
system = "x86_64-linux";
modules = [
./configuration.nix
./hardware-configuration.nix
];
};
nixosConfigurations.live = nixpkgs.lib.nixosSystem {
system = "x86_64-linux";
modules = [
(nixpkgs + "/nixos/modules/installer/cd-dvd/installation-cd-minimal.nix")
./configuration.nix
];
};
};
}

View file

@ -0,0 +1,51 @@
# Do not modify this file! It was generated by nixos-generate-config
# and may be overwritten by future invocations. Please make changes
# to /etc/nixos/configuration.nix instead.
{ config, lib, pkgs, modulesPath, ... }:
{
imports = [ ];
boot.initrd.availableKernelModules = [ "ata_piix" "vmw_pvscsi" "ahci" "sd_mod" "sr_mod" ];
boot.initrd.kernelModules = [ ];
boot.kernelModules = [ ];
boot.extraModulePackages = [ ];
fileSystems."/" =
{ device = "/dev/disk/by-uuid/2135c59d-9c2d-487c-9c4e-0f566fa9d316";
fsType = "btrfs";
options = [ "subvol=@" ];
};
fileSystems."/boot" =
{ device = "/dev/disk/by-uuid/7E60-8E0B";
fsType = "vfat";
options = [ "fmask=0077" "dmask=0077" ];
};
swapDevices = [ ];
# Enables DHCP on each ethernet and wireless interface. In case of scripted networking
# (the default) this is the recommended approach. When using systemd-networkd it's
# still possible to use this option, but it's recommended to use it in conjunction
# with explicit per-interface declarations with `networking.interfaces.<interface>.useDHCP`.
networking.useDHCP = lib.mkDefault false;
# networking.interfaces.ens33.useDHCP = lib.mkDefault true;
networking.interfaces.ens33 = {
ipv4.addresses = [{
address = "172.18.154.50";
prefixLength = 24;
}];
};
# Enable networking
networking.networkmanager.enable = true;
networking.defaultGateway = {
address = "172.18.154.1";
interface = "ens33";
};
networking.nameservers = [ "64.102.6.247" ];
networking.search = [ "cisco.com" ];
nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux";
}

View file

@ -1,2 +0,0 @@
*.tar.gz

View file

@ -1,19 +0,0 @@
# ISE Utility Bash Scripts
Currently these set of scripts are able to:
- Login to ISE
- Logout of ISE
- Enable/Disable ERS API
- Create new OCSP Profile
- Disable admin password requirements such as expiration and complexity
## Usage
1. Change `HOSTNAME` in `login.bash` to the IP address/FQDN of your ISE server.
2. Read the script to understand what it is doing and modify any variables that you need to.
1. For example, `create_new_ocsp_profile.bash` requires you to modify the following:
- CRUD="Create"
- OCSP_PRIMARY_URL="[2001:420:27ff:fff9::7]:5000"
- OCSP_SERVICE_NAME="ggg"
- SELECTED_ITEM_NAME="ggg"
2. Execute any of the scripts that you want to modify settings on.

View file

@ -1,23 +0,0 @@
#!/bin/bash
source ./login.bash
# Make OCSP request
echo -e "Updating OCSP Client Profile"
CRUD="Create" # This can be Create or Edit
OCSP_PRIMARY_URL="[2001:420:27ff:fff9::7]:5000"
OCSP_SERVICE_NAME="ggg"
SELECTED_ITEM_NAME="ggg" # This one is needed when you edit an existing OCSP service
curl -k 'https://diorite.cisco.com/admin/ocspServicesAction.do' -X POST \
-H 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:126.0) Gecko/20100101 Firefox/126.0' \
-H 'Accept: */*' -H 'Accept-Language: en-US,en;q=0.5' \
-H 'Accept-Encoding: gzip, deflate, br, zstd' \
-H '_QPH_: Y29tbWFuZD1zYXZl' -H 'Content-Type: application/x-www-form-urlencoded' \
-H 'X-Requested-With: XMLHttpRequest, XMLHttpRequest' \
-H "OWASP_CSRFTOKEN: ${CSRFTOKEN}" \
-H 'Connection: keep-alive' \
-H "Cookie: APPSESSIONID=${APPSESSIONID}; MNTLA_JWT_TOKEN=${JWT_TOKEN}" \
--data-raw "crud=$CRUD&selectedItemName=$SELECTED_ITEM_NAME&ocspServicesStub.failoverToSecondary=false&ocspServicesStub.alwaysAccessPrimaryFirst=true&ocspServicesStub.primaryNonceExtensions=true&ocspServicesStub.primaryValidateResponseSignature=true&ocspServicesStub.secondaryNonceExtensions=true&ocspServicesStub.secondaryValidateResponseSignature=true&ocspServicesStub.selectedOCSPConfig=OCSP_RESPONDER&ocspServicesStub.enableNonceExtensionSupportAia=true&ocspServicesStub.validateResponseSignatureAia=true&ocspServicesStub.name=$OCSP_SERVICE_NAME&ocspServicesStub.description=&ocspServicesStub.primaryURL=$OCSP_PRIMARY_URL&primaryNonceExtensionsCB=on&primaryValidateResponseSignatureCB=on&ocspServicesStub.cacheTimeout=1440" 2>/dev/null | jq
source ./logout.bash

View file

@ -1,17 +0,0 @@
#!/bin/bash
source ./login.bash
# _QPC_ is a base64 encoded string that contains the CSRF token
QPC=$(printf "command=editAuthSubmit&OWASP_CSRFTOKEN=$CSRFTOKEN" | $BASE64 -w0)
curl "https://$HOSTNAME/admin/adminAuthSettingsAction.do" --compressed --insecure -X POST \
-H 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:128.0) Gecko/20100101 Firefox/128.0' \
-H 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/png,image/svg+xml,*/*;q=0.8' \
-H 'Accept-Language: en-US,en;q=0.5' -H 'Accept-Encoding: gzip, deflate, br, zstd' \
-H 'Content-Type: multipart/form-data; boundary=---------------------------1799742068132450087154255035' \
-H "Cookie: APPSESSIONID=$APPSESSIONID; _QPC_=$QPC; MNTLA_JWT_TOKEN=$JWT_TOKEN" \
--data-binary $'-----------------------------1799742068132450087154255035\r\nContent-Disposition: form-data; name="adminAuthSettingsStub.passwordLengthTxt"\r\n\r\n4\r\n-----------------------------1799742068132450087154255035\r\nContent-Disposition: form-data; name="adminAuthSettingsStub.passwordNotUserCharsTxt"\r\n\r\n\r\n-----------------------------1799742068132450087154255035\r\nContent-Disposition: form-data; name="adminAuthSettingsStub.isNewDictFile"\r\n\r\nfalse\r\n-----------------------------1799742068132450087154255035\r\nContent-Disposition: form-data; name="adminAuthSettingsStub.passwordHistoryTxt"\r\n\r\n3\r\n-----------------------------1799742068132450087154255035\r\nContent-Disposition: form-data; name="adminAuthSettingsStub.passwordReuse"\r\n\r\n15\r\n-----------------------------1799742068132450087154255035\r\nContent-Disposition: form-data; name="adminAuthSettingsStub.passwordDisableUserAccountTxt"\r\n\r\n45\r\n-----------------------------1799742068132450087154255035\r\nContent-Disposition: form-data; name="adminAuthSettingsStub.passwordDisplayReminderTxt"\r\n\r\n30\r\n-----------------------------1799742068132450087154255035\r\nContent-Disposition: form-data; name="OWASP_CSRFTOKEN"\r\n\r\n""\r\n-----------------------------1799742068132450087154255035--\r\n'
source ./logout.bash

View file

@ -1,27 +0,0 @@
#!/bin/bash
source ./login.bash
# Make the API call to enable ERS API
ENABLE_ERS_API='true'
curl -k "https://$HOSTNAME/admin/ersSettingsAction.do" -X POST \
-H 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:128.0) Gecko/20100101 Firefox/128.0' \
-H 'Accept: */*' \
-H 'Accept-Language: en-US,en;q=0.5' \
-H 'Accept-Encoding: gzip, deflate, br, zstd' \
-H '_QPH_: Y29tbWFuZD1zdWJtaXRBUElTZXJ2aWNlU2V0dGluZ3M=' \
-H 'Content-Type: application/x-www-form-urlencoded' \
-H 'X-Requested-With: XMLHttpRequest, XMLHttpRequest' \
-H "OWASP_CSRFTOKEN: $CSRFTOKEN" \
-H "Origin: https://$HOSTNAME" \
-H 'Connection: keep-alive' \
-H 'Referer: https://diorite.cisco.com/admin/' \
-H "Cookie: APPSESSIONID=$APPSESSIONID; MNTLA_JWT_TOKEN=$JWT_TOKEN" \
-H 'Sec-Fetch-Dest: empty' \
-H 'Sec-Fetch-Mode: cors' \
-H 'Sec-Fetch-Site: same-origin' \
-H 'Priority: u=0' \
--data-raw "PAPEnabled=$ENABLE_ERS_API&OWASP_CSRFTOKEN=$CSRFTOKEN" 2>/dev/null | awk '{$1=$1};1' | awk '{printf "%s",$0} END {print ""}' | awk '{gsub(/'\''/, "\""); print}' | jq
source ./logout.bash

View file

@ -1,14 +0,0 @@
#!/bin/bash
JOB_NAME=STO_Sparta_sysdevST02
JOB_SCRIPT=ipv6_policy_set_radius_attributes.py
BRANCH_NAME=radius_ipv6_ise_1971
curl -k -X POST https://spotlight-jenkins.cisco.com/job/STO_Sparta/job/$JOB_NAME/buildWithParameters \
--user iuser:11cdf2ceeab4fd7bd0e3d3bca18066ad2a \
--data jobname=$JOB_SCRIPT \
--data branch=$BRANCH_NAME \
--data revert=true \
--data revert_option=init/standalone \
--data build=3.4.0.379

View file

@ -1,74 +0,0 @@
#!/bin/bash
HOSTNAME="sto-sparta-ise-3.cisco.com"
USERNAME="admin"
PASSWORD="Lab@12345"
APPSESSIONID=0
CSRFTOKEN=0
JWT_TOKEN=0
QPC=0
GREP="grep"
BASE64="base64"
if [[ "$OSTYPE" == "darwin"* ]]; then
echo -e "Using g* tools because of course macOS"
GREP="ggrep"
BASE64="gbase64"
fi
# Get the CSRF token and APPSESSIONID
echo -e "Getting CSRF token and initial APPSESSIONID"
output=$(curl -c - -k -L -s --compressed --request POST \
--url https://$HOSTNAME/admin/JavaScriptServlet \
--header 'Accept: */*' \
--header 'Accept-Encoding: gzip, deflate, br, zstd' \
--header 'Accept-Language: en-US,en;q=0.5' \
--header 'Connection: keep-alive' \
--header 'Content-Length: 0' \
--header 'DNT: 1' \
--header 'FETCH-CSRF-TOKEN: 1' \
--header 'Origin: CWILLIA5-M-WJ2C' \
--header 'Sec-Fetch-Dest: empty' \
--header 'Sec-GPC: 1' \
--header 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:126.0) Gecko/20100101 Firefox/126.0' 2>/dev/null )
CSRFTOKEN=$(echo $output | $GREP -oP '(?<=OWASP_CSRFTOKEN:)[^#]*')
APPSESSIONID=$(echo $output | awk '{print $NF}')
echo -e "CSRFTOKEN: $CSRFTOKEN"
echo -e "APPSESSIONID: $APPSESSIONID"
# Get the JWT token
echo -e "Logging in, getting JWT token and updating APPSESSIONID"
output=$(curl -k -c - --request POST \
--cookie "APPSESSIONID=$APPSESSIONID" \
--url https://$HOSTNAME/admin/LoginAction.do \
--header 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8' \
--header 'Accept-Encoding: gzip, deflate, br, zstd' \
--header 'Accept-Language: en-US,en;q=0.5' \
--header 'Connection: keep-alive' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--header 'DNT: 1' \
--header 'Priority: u=1' \
--header 'Sec-Fetch-Dest: document' \
--header 'Sec-Fetch-Mode: navigate' \
--header 'Sec-Fetch-User: ?1' \
--header 'Sec-GPC: 1' \
--header 'Upgrade-Insecure-Requests: 1' \
--header 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:126.0) Gecko/20100101 Firefox/126.0' \
--data username=$USERNAME \
--data password=$PASSWORD \
--data samlLogin=false \
--data rememberme=off \
--data name=$USERNAME \
--data password=$PASSWORD \
--data authType=Internal \
--data CSRFTokenNameValue=OWASP_CSRFTOKEN=$CSRFTOKEN \
--data OWASP_CSRFTOKEN=$CSRFTOKEN \
--data locale=en \
--data hasSelectedLocale=false 2>/dev/null)
# APPSESSIONID Gets updated here so we need to reassign APPSESSIONID
APPSESSIONID=$(echo -e "$output" | awk '/APPSESSIONID/ {print $7}')
JWT_TOKEN=$(echo -e "$output" | awk '/MNTLA_JWT_TOKEN/ {print $7}')
echo -e "JWT_TOKEN: $JWT_TOKEN"

View file

@ -1,17 +0,0 @@
#!/bin/bash
# Logging out
echo -e "Logging out"
curl -k "https://$HOSTNAME/admin/logout.jsp" \
-H 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:128.0) Gecko/20100101 Firefox/128.0' \
-H 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/png,image/svg+xml,*/*;q=0.8' \
-H 'Accept-Language: en-US,en;q=0.5' \
-H 'Accept-Encoding: gzip, deflate, br, zstd' \
-H 'Connection: keep-alive' \
-H "Cookie: APPSESSIONID=$APPSESSIONID; MNTLA_JWT_TOKEN=$JWT_TOKEN" \
-H 'Upgrade-Insecure-Requests: 1' \
-H 'Sec-Fetch-Dest: document' \
-H 'Sec-Fetch-Mode: navigate' \
-H 'Sec-Fetch-Site: same-origin' \
-H 'Sec-Fetch-User: ?1' \
-H 'Priority: u=0, i'

View file

@ -1,2 +0,0 @@
/target
*.log

View file

@ -1 +0,0 @@
pypy@3.10.14

View file

@ -1,140 +0,0 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "aho-corasick"
version = "1.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916"
dependencies = [
"memchr",
]
[[package]]
name = "const_format"
version = "0.2.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e3a214c7af3d04997541b18d432afaff4c455e79e2029079647e72fc2bd27673"
dependencies = [
"const_format_proc_macros",
]
[[package]]
name = "const_format_proc_macros"
version = "0.2.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c7f6ff08fd20f4f299298a28e2dfa8a8ba1036e6cd2460ac1de7b425d76f2500"
dependencies = [
"proc-macro2",
"quote",
"unicode-xid",
]
[[package]]
name = "ise_logparser"
version = "0.1.0"
dependencies = [
"const_format",
"lazy_static",
"nom",
"nom-regex",
"regex",
]
[[package]]
name = "lazy_static"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
[[package]]
name = "memchr"
version = "2.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
[[package]]
name = "minimal-lexical"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
[[package]]
name = "nom"
version = "7.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a"
dependencies = [
"memchr",
"minimal-lexical",
]
[[package]]
name = "nom-regex"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72e5c7731c4c1370b61604ed52a2475e861aac9e08dec9f23903d4ddfdc91c18"
dependencies = [
"nom",
"regex",
]
[[package]]
name = "proc-macro2"
version = "1.0.86"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.36"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7"
dependencies = [
"proc-macro2",
]
[[package]]
name = "regex"
version = "1.10.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619"
dependencies = [
"aho-corasick",
"memchr",
"regex-automata",
"regex-syntax",
]
[[package]]
name = "regex-automata"
version = "0.4.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df"
dependencies = [
"aho-corasick",
"memchr",
"regex-syntax",
]
[[package]]
name = "regex-syntax"
version = "0.8.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b"
[[package]]
name = "unicode-ident"
version = "1.0.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
[[package]]
name = "unicode-xid"
version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c"

View file

@ -1,11 +0,0 @@
[package]
name = "ise_logparser"
version = "0.1.0"
edition = "2021"
[dependencies]
const_format = "0.2.32"
lazy_static = "1.5.0"
nom = "7.1.3"
nom-regex = "0.2.0"
regex = "1.10.6"

View file

@ -1,3 +0,0 @@
# ise-logparser
Describe your project here.

View file

@ -1,13 +0,0 @@
```
pre_test_output := .*
start_marker := 'JOB START'
test_output := .*
end_marker := 'JOB END'
post_test_output := .*
report_marker := 'Report'
report := .*
summary_marker := 'Result Summary'
summary := .*
details_marker := 'Result Details'
details := .*
```

View file

@ -1,33 +0,0 @@
[project]
name = "ise-logparser"
version = "0.1.0"
description = "Add your description here"
authors = [
{ name = "Mira Kristipati", email = "akristip@cisco.com" }
]
dependencies = [
"parsy>=2.1",
"icecream>=2.1.3",
"python-dotenv>=1.0.1",
"mypy>=1.11.1",
"setuptools>=72.1.0",
"colorama>=0.4.6",
"types-colorama>=0.4.15.20240311",
"flameprof>=0.4",
]
readme = "README.md"
requires-python = ">= 3.8"
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
[tool.rye]
managed = true
dev-dependencies = []
[tool.hatch.metadata]
allow-direct-references = true
[tool.hatch.build.targets.wheel]
packages = ["src/ise_logparser"]

View file

@ -1,43 +0,0 @@
# generated by rye
# use `rye lock` or `rye sync` to update this lockfile
#
# last locked with the following flags:
# pre: false
# features: []
# all-features: false
# with-sources: false
# generate-hashes: false
# universal: false
-e file:.
asttokens==2.4.1
# via icecream
colorama==0.4.6
# via icecream
# via ise-logparser
executing==2.0.1
# via icecream
flameprof==0.4
# via ise-logparser
icecream==2.1.3
# via ise-logparser
mypy==1.11.1
# via ise-logparser
mypy-extensions==1.0.0
# via mypy
parsy==2.1
# via ise-logparser
pygments==2.18.0
# via icecream
python-dotenv==1.0.1
# via ise-logparser
setuptools==72.1.0
# via ise-logparser
six==1.16.0
# via asttokens
tomli==2.0.1
# via mypy
types-colorama==0.4.15.20240311
# via ise-logparser
typing-extensions==4.12.2
# via mypy

View file

@ -1,43 +0,0 @@
# generated by rye
# use `rye lock` or `rye sync` to update this lockfile
#
# last locked with the following flags:
# pre: false
# features: []
# all-features: false
# with-sources: false
# generate-hashes: false
# universal: false
-e file:.
asttokens==2.4.1
# via icecream
colorama==0.4.6
# via icecream
# via ise-logparser
executing==2.0.1
# via icecream
flameprof==0.4
# via ise-logparser
icecream==2.1.3
# via ise-logparser
mypy==1.11.1
# via ise-logparser
mypy-extensions==1.0.0
# via mypy
parsy==2.1
# via ise-logparser
pygments==2.18.0
# via icecream
python-dotenv==1.0.1
# via ise-logparser
setuptools==72.1.0
# via ise-logparser
six==1.16.0
# via asttokens
tomli==2.0.1
# via mypy
types-colorama==0.4.15.20240311
# via ise-logparser
typing-extensions==4.12.2
# via mypy

View file

@ -1,323 +0,0 @@
#!/usr/bin/env python3
from __future__ import annotations
import cProfile
import argparse
import logging
import os
import profile
import re
from pathlib import Path
from typing import cast
import time
from icecream import ic
import pstats
import parsy as ps
from colorama import Back, Fore, Style
from parsy import Parser, generate, peek, regex, seq, string
from functools import reduce
ic.configureOutput(includeContext=True)
LEVEL_UNKNOWN = 255
NEWLINE = string("\n")
SPACE = string(" ")
class Config(dict[str, str]):
class LevelAction(argparse.Action):
def __call__(self, parser, namespace, values, option_string=None) -> None:
_ = (parser, option_string)
values = cast(str, values)
setattr(namespace, self.dest, get_debug_level_const(values.upper())[0])
def __init__(self) -> None:
self.dict = {}
if os.path.exists(".env"):
from dotenv import dotenv_values
self.dict = {
k: v for k, v in dotenv_values(".env").items() if v is not None
}
parser = argparse.ArgumentParser()
if not ("LOGFILE" in self.dict or "LOGFILE" in os.environ):
parser.add_argument(
"LOGFILE",
type=Path,
)
parser.add_argument("-q", "--query", dest="QUERY")
parser.add_argument(
"-l",
"--level",
dest="LOGLEVEL",
type=str,
choices=["debug", "info", "warn", "err", "crit", "unk"],
default=logging.INFO,
action=self.LevelAction,
)
self.dict.update(parser.parse_args().__dict__)
def __getitem__(self, key: str, /) -> str:
try:
return self.dict[key]
except KeyError:
return os.environ[key]
def __setitem__(self, _key: str, _value: str, /) -> None:
msg = "Config is read-only"
raise NotImplementedError(msg)
def __delitem__(self, _: str, /) -> None:
msg = "Config is read-only"
raise NotImplementedError(msg)
def __iter__(self):
return iter(self.dict)
def __len__(self) -> int:
return len(self.dict)
def __repr__(self) -> str:
return self.dict.__repr__()
"""
Formatting functions
"""
def colorize_status(status: str) -> str:
if "PASS" in status:
return Fore.GREEN + status + Style.RESET_ALL
elif "FAIL" in status:
return Fore.RED + status + Style.RESET_ALL
elif "ERROR" in status:
return Fore.BLACK + Back.RED + status + Style.RESET_ALL
return status
def get_debug_level_const(level: str) -> tuple[int, str]:
if "DEBUG" in level:
return (logging.DEBUG, level)
elif "INFO" in level:
return (logging.INFO, level)
elif "WARN" in level:
return (logging.WARNING, level)
elif "ERR" in level:
return (logging.ERROR, level)
elif "CRIT" in level:
return (logging.CRITICAL, level)
else:
return (LEVEL_UNKNOWN, level)
def colorize_by_level(level: str, text: str) -> str:
if "DEBUG" in level:
return Style.DIM + text + Style.RESET_ALL
elif "INFO" in level:
return Style.BRIGHT + text + Style.RESET_ALL
elif "WARN" in level:
return Fore.YELLOW + text + Style.RESET_ALL
elif "ERR" in level:
return Fore.RED + text + Style.RESET_ALL
elif "CRIT" in level:
return Style.BRIGHT + Back.RED + Fore.BLACK + text + Style.RESET_ALL
else:
return Fore.BLUE + text + Style.RESET_ALL
# return level
"""
Output functions
"""
class TestPrinterBuilder:
loglevel: int = logging.NOTSET
query: str | re.Pattern[str] | None = None
def __call__(
self, ts: str, level: tuple[int, str], src: str, msg: str
) -> str | None:
level_name = level[1]
if (level[0] >= self.loglevel) or (
self.query is not None and re.search(self.query, msg)
):
res = f"{ts}\t{Fore.BLACK + Back.WHITE + level[1] + Style.RESET_ALL}\t{colorize_by_level(level_name,f'{src}: {msg}')}"
print(res)
return res
return ""
def with_loglevel(self, loglevel: int) -> TestPrinterBuilder:
self.loglevel = loglevel
return self
def with_query(self, query: str | re.Pattern) -> TestPrinterBuilder:
self.query = query
return self
"""
Parser defs
"""
def block_parser(text: str) -> Parser:
return regex(rf"^.*\n^.*{text}.*$\n.*", re.MULTILINE)
timestamp: Parser = regex(
r"^\d{4}-\d{2}-\d{2}.\d{2}:\d{2}:\d{2}(\+\d{2}:\d{2})?(,\d{3})?", re.MULTILINE
).skip(string(":").optional())
debug_level: Parser = regex(r"[A-Za-z0-9_%-]+").skip(string(":").optional())
start_block = block_parser("EASYPY JOB START")
end_block = block_parser("EASYPY JOB END")
report_block = block_parser("Easypy Report")
summary_block = block_parser("Task Result Summary")
details_block = block_parser("Task Result Details")
message = ps.any_char.until(ps.alt(ps.peek(timestamp), ps.eof)).concat()
@generate
def test_output_line():
ts = yield timestamp.skip(SPACE)
level = yield debug_level.skip(SPACE)
src = yield (
string("[").then(regex(r"[A-Za-z_0-9]+")).skip(string("] ")).optional()
)
msg = yield message.map(lambda x: x.rstrip())
print_test_line(ts, get_debug_level_const(level), src, msg)
return ps.success("")
@generate
def test_details():
indent = yield (
NEWLINE.optional()
.skip(string("|").optional())
.skip(SPACE.at_least(1))
.then(ps.seq(ps.char_from("|`"), string("--").skip(ps.whitespace)).concat())
)
test_name = yield ps.any_char.until(ps.whitespace).skip(ps.whitespace).concat()
test_results = yield ps.letter.many().skip(NEWLINE).concat()
print(f" {'' * (len(indent)//2)}{colorize_status(test_results)}\t{test_name}")
return {"test_results": test_results, "test_name": test_name}
@generate
def subtask_details():
subtask_name = (
yield seq(ps.alt(string("|--"), string("`--")), ps.whitespace)
.then(ps.any_char.until(ps.whitespace))
.skip(ps.whitespace)
.concat()
)
subtask_result = yield ps.letter.many().skip(NEWLINE).concat()
print(f"{colorize_status(subtask_result)}\t{subtask_name}")
tests = yield test_details.many()
return {
"subtask_result": subtask_result,
"subtask_name": subtask_name,
"tests": tests,
}
@generate
def task_details():
task_number = (
yield ps.any_char.until(string(":"))
.skip(string(":"))
.skip(ps.whitespace)
.concat()
)
task_name = yield ps.any_char.until(ps.whitespace).concat().skip(ps.whitespace)
print(f"{task_number}\t {Style.BRIGHT + task_name + Style.RESET_ALL}")
subtasks = yield subtask_details.many()
return {"task_number": task_number, "task_name": task_name, "subtasks": subtasks}
@generate
# NOTE: Uncomment the print statements if you actually care what's in these sections
def sections():
header = yield seq(
ps.any_char.until(peek(timestamp)), # TODO: output this
test_output_line.until(start_block).skip(start_block).skip(NEWLINE),
).combine(list.__add__).concat()
ic(elapsed())
test_output = yield test_output_line.until(end_block).skip(end_block).skip(NEWLINE)
ic(elapsed())
# exit(1)
post_test = yield ps.any_char.until(report_block).skip(report_block).concat()
ic(elapsed())
# print(post_test)
report = yield ps.any_char.until(summary_block).skip(summary_block).concat()
ic(elapsed())
# print(report)
summary = yield ps.any_char.until(details_block).skip(details_block).concat()
ic(elapsed())
# print(summary)
details = yield task_details.many()
ic(elapsed())
etc = yield ps.any_char.until(ps.eof).concat()
ic(elapsed())
return {
"header": header,
"test_output": test_output,
"post_test": post_test,
"report": report,
"summary": summary,
"details": details,
"etc": etc,
}
def elapsed():
global current
global prev
current = time.time()
elapsed = current - prev
prev = current
return elapsed
# TODO: make this work with streams
def main():
global current
global prev
current = time.time()
prev = time.time()
config = Config()
with Path(config["LOGFILE"]).open() as f:
log = f.read()
global print_test_line
print_test_line = TestPrinterBuilder()
if loglevel := config["LOGLEVEL"]:
print_test_line = print_test_line.with_loglevel(cast(int, loglevel))
if query := config.get("QUERY"):
print_test_line = print_test_line.with_query(query)
sections.parse(log)
if __name__ == "__main__":
# import io
# pr = cProfile.Profile()
# pr.enable()
main()
# pr.disable()
# s = io.StringIO()
# ps = pstats.Stats(pr)
# ps.dump_stats("test.stats")
# print(s.getvalue())

View file

@ -1,69 +0,0 @@
use std::{cell::OnceCell, sync::OnceLock};
use lazy_static::lazy_static;
use nom::{
bytes::complete::take_while1, character::complete::anychar, error::ErrorKind, multi::many_till,
IResult,
};
use nom_regex::str::re_match;
use regex::Regex;
struct Sections {
header: String,
}
static TIMESTAMP_REGEX: OnceLock<Regex> = OnceLock::new();
static START_BLOCK_REGEX: OnceLock<Regex> = OnceLock::new();
static END_BLOCK_REGEX: OnceLock<Regex> = OnceLock::new();
fn timestamp<'a>(input: &'a str) -> IResult<&'a str, &'a str> {
re_match::<nom::error::Error<&str>>(TIMESTAMP_REGEX.get().unwrap().clone())(input)
}
fn debug_level(input: &str) -> IResult<&str, &str> {
take_while1(|c: char| c.is_alphabetic() || ['_', '-', '%'].contains(&c))(input)
}
fn start_block(input: &str) -> IResult<&str, &str> {
re_match::<nom::error::Error<&str>>(START_BLOCK_REGEX.get().unwrap().clone())(input)
}
fn end_block(input: &str) -> IResult<&str, &str> {
re_match::<nom::error::Error<&str>>(END_BLOCK_REGEX.get().unwrap().clone())(input)
}
fn test_output_line(input: &str) -> IResult<&str, &str> {
let (input, timestamp) = timestamp(input)?;
let (input, _) = nom::character::complete::char(' ')(input)?;
let (input, level) = debug_level(input)?;
let (input, _) = nom::character::complete::char(' ')(input)?;
let (input, _) = nom::character::complete::line_ending(input)?;
let (input, msg) = message(input)?;
IResult::Ok((input, ""))
}
fn header(input: &str) -> IResult<&str, String> {
// any_char.until(timestamp).concat()
let (_, (b, rest)) = many_till(anychar, timestamp)(input)?;
let joined = b.iter().collect::<String>();
// test_output_line.until(start_block)
let (_, (c, rest)) = many_till(test_output_line, start_block)(rest)?;
print!("{}", rest);
IResult::Ok((input, joined))
}
fn sections(log: &str) -> IResult<&str, Sections> {
let (_log, _header) = header(log)?;
todo!()
}
fn main() {
TIMESTAMP_REGEX
.set(Regex::new(r"^\d{4}-\d{2}-\d{2}.\d{2}:\d{2}:\d{2}(\+\d{2}:\d{2})?(,\d{3})?").unwrap())
.unwrap();
START_BLOCK_REGEX
.set(Regex::new(r"^.*\n^.*EASYPY JOB START.*$\n.*").unwrap())
.unwrap();
let file = include_str!("../consoleText");
header(file);
}

View file

@ -1,2 +0,0 @@
.venv
.ruff_cache

View file

@ -1,13 +0,0 @@
{ pkgs ? import <nixpkgs> { } }:
pkgs.mkShell {
packages = [
(pkgs.python3.withPackages (python-pkgs: [
python-pkgs.pexpect
python-pkgs.icecream
python-pkgs.mypy
# python-pkgs.ruff
]))
pkgs.openssh
];
}

View file

@ -1,74 +0,0 @@
#!/usr/bin/env python3
import argparse
import logging
import re
import sys
from logging import getLogger
from typing import List
import pexpect
def login(username: str, password: str) -> pexpect.spawn:
child = pexpect.spawn(
f"ssh -i /dev/null {username}@{addr}",
encoding="utf-8",
logfile=sys.stdout,
)
child.expect("password:")
child.sendline(password)
return child
def change_password(child: pexpect.spawn, old_password: str, new_password: str) -> None:
child.expect("password:")
child.sendline(old_password)
child.expect("[Nn]ew password:")
child.sendline(new_password)
child.expect("[Nn]ew password:")
child.sendline(new_password)
child.expect_list([re.compile("success"), re.compile(f"{username}#")])
logger.info("Changing password to %s", new_password)
def set_new_password_and_verify(
child: pexpect.spawn,
password: str,
new_password: str,
) -> pexpect.spawn:
change_password(child, password, new_password)
child = login(username, new_password)
child.expect(f"{username}#")
return child
if __name__ == "__main__":
logger = getLogger(__name__)
logger.level = logging.DEBUG
parser = argparse.ArgumentParser()
parser.add_argument("addr", help="IP address of the device")
parser.add_argument("username", help="Username of the device", default="admin")
parser.add_argument("password", help="Password of the device")
args = parser.parse_args()
username = args.username
password = args.password
addr = args.addr
try:
passwords: List[str] = [password] + [
"".join([f"{i}{j}" for i in password]) for j in range(4)
]
child = login(username, password)
new_password = passwords.pop()
child = set_new_password_and_verify(child, password, new_password)
while len(passwords):
password = new_password
child.sendline("password")
new_password = passwords.pop()
child = set_new_password_and_verify(child, password, new_password)
except Exception:
logger.exception("man idek anymore, file a bug")

44
user.nix Normal file
View file

@ -0,0 +1,44 @@
# User config definitions
{ config, pkgs, lib, ... }:
{
options = {
calliope = {
hostname = lib.mkOption {
type = string;
default = "calliope";
};
ipv4Address = lib.mkOption {
type = string;
};
# TODO:
password = lib.mkOption {};
cec = lib.mkOption {
type = string;
username = lib.mkOption {
type = string;
# TODO: make this default to CEC
};
defaultShell = mkPackageOption pkgs "shell" {
default = [ "bash" ];
};
};
# TODO:
authorizedKeys = lib.mkOption {};
# TODO:
sshIdentities = lib.mkOption {};
}
config = {
networking.hostName = options.calliope.hostname;
# TODO: set the ipv4 address, and figure out how to set this without knowing interface name
# TODO: set default gateway
# TODO: use CEC to set up git identity
# TODO: set default shell
# TODO: set authorized_keys
# TODO: set SSH Private keys
};
}