move in chris's scripts, add initial log parser
This commit is contained in:
parent
5a16d7e9bf
commit
23172e6008
19 changed files with 392 additions and 1 deletions
2
ise/ISE-bash-scripts/.gitignore
vendored
Normal file
2
ise/ISE-bash-scripts/.gitignore
vendored
Normal file
|
@ -0,0 +1,2 @@
|
|||
*.tar.gz
|
||||
|
19
ise/ISE-bash-scripts/README.md
Normal file
19
ise/ISE-bash-scripts/README.md
Normal file
|
@ -0,0 +1,19 @@
|
|||
# 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.
|
||||
|
23
ise/ISE-bash-scripts/create_new_ocsp_profile.bash
Executable file
23
ise/ISE-bash-scripts/create_new_ocsp_profile.bash
Executable file
|
@ -0,0 +1,23 @@
|
|||
#!/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
|
||||
|
17
ise/ISE-bash-scripts/disable_admin_annoyances.bash
Executable file
17
ise/ISE-bash-scripts/disable_admin_annoyances.bash
Executable file
|
@ -0,0 +1,17 @@
|
|||
#!/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
|
||||
|
27
ise/ISE-bash-scripts/enable_ers_api.bash
Executable file
27
ise/ISE-bash-scripts/enable_ers_api.bash
Executable file
|
@ -0,0 +1,27 @@
|
|||
#!/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
|
||||
|
14
ise/ISE-bash-scripts/execute_jenkins_job.bash
Executable file
14
ise/ISE-bash-scripts/execute_jenkins_job.bash
Executable file
|
@ -0,0 +1,14 @@
|
|||
#!/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
|
||||
|
74
ise/ISE-bash-scripts/login.bash
Executable file
74
ise/ISE-bash-scripts/login.bash
Executable file
|
@ -0,0 +1,74 @@
|
|||
#!/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"
|
||||
|
17
ise/ISE-bash-scripts/logout.bash
Executable file
17
ise/ISE-bash-scripts/logout.bash
Executable file
|
@ -0,0 +1,17 @@
|
|||
#!/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'
|
2
ise/ise_logparser/.gitignore
vendored
Normal file
2
ise/ise_logparser/.gitignore
vendored
Normal file
|
@ -0,0 +1,2 @@
|
|||
/target
|
||||
*.log
|
1
ise/ise_logparser/.python-version
Normal file
1
ise/ise_logparser/.python-version
Normal file
|
@ -0,0 +1 @@
|
|||
3.12.3
|
3
ise/ise_logparser/README.md
Normal file
3
ise/ise_logparser/README.md
Normal file
|
@ -0,0 +1,3 @@
|
|||
# ise-logparser
|
||||
|
||||
Describe your project here.
|
13
ise/ise_logparser/notes.md
Normal file
13
ise/ise_logparser/notes.md
Normal file
|
@ -0,0 +1,13 @@
|
|||
```
|
||||
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 := .*
|
||||
```
|
28
ise/ise_logparser/pyproject.toml
Normal file
28
ise/ise_logparser/pyproject.toml
Normal file
|
@ -0,0 +1,28 @@
|
|||
[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",
|
||||
]
|
||||
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"]
|
28
ise/ise_logparser/requirements-dev.lock
Normal file
28
ise/ise_logparser/requirements-dev.lock
Normal file
|
@ -0,0 +1,28 @@
|
|||
# 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
|
||||
executing==2.0.1
|
||||
# via icecream
|
||||
icecream==2.1.3
|
||||
# via ise-logparser
|
||||
parsy==2.1
|
||||
# via ise-logparser
|
||||
pygments==2.18.0
|
||||
# via icecream
|
||||
python-dotenv==1.0.1
|
||||
# via ise-logparser
|
||||
six==1.16.0
|
||||
# via asttokens
|
28
ise/ise_logparser/requirements.lock
Normal file
28
ise/ise_logparser/requirements.lock
Normal file
|
@ -0,0 +1,28 @@
|
|||
# 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
|
||||
executing==2.0.1
|
||||
# via icecream
|
||||
icecream==2.1.3
|
||||
# via ise-logparser
|
||||
parsy==2.1
|
||||
# via ise-logparser
|
||||
pygments==2.18.0
|
||||
# via icecream
|
||||
python-dotenv==1.0.1
|
||||
# via ise-logparser
|
||||
six==1.16.0
|
||||
# via asttokens
|
93
ise/ise_logparser/src/main.py
Executable file
93
ise/ise_logparser/src/main.py
Executable file
|
@ -0,0 +1,93 @@
|
|||
#!/usr/bin/env python3
|
||||
import re
|
||||
from pathlib import Path
|
||||
from dotenv import dotenv_values
|
||||
import parsy as ps
|
||||
from icecream import ic
|
||||
import os
|
||||
from pprint import pprint as print
|
||||
from parsy import regex, seq
|
||||
|
||||
# TODO: (akristip) refactor these to use `<<` instead of capture groups
|
||||
parse_header = regex(
|
||||
r"(.*)(^[^\n]*-+\n.*EASYPY JOB START.*?-+\|\n)",
|
||||
re.MULTILINE | re.DOTALL,
|
||||
1,
|
||||
)
|
||||
parse_test_output = regex(
|
||||
r"(.*)(^[^\n]*-+\n.*EASYPY JOB END.*?-+\|)",
|
||||
re.MULTILINE | re.DOTALL,
|
||||
1,
|
||||
)
|
||||
parse_post_test = regex(
|
||||
r"(.*)(\+-+\+\n\| +Easypy Report +\|\n\+-+\+)",
|
||||
re.MULTILINE | re.DOTALL,
|
||||
1,
|
||||
)
|
||||
parse_report = regex(
|
||||
r"(.*)(\+-+\+\n\| +Task Result Summary +\|\n\+-+\+)",
|
||||
re.MULTILINE | re.DOTALL,
|
||||
1,
|
||||
)
|
||||
parse_summary = regex(
|
||||
r"(.*)(\+-+\+\n\| +Task Result Details +\|\n\+-+\+)",
|
||||
re.MULTILINE | re.DOTALL,
|
||||
1,
|
||||
)
|
||||
|
||||
timestamp = regex(r"\d{4}-\d{2}-\d{2}.\d{2}:\d{2}:\d{2}(,\d{3})?")
|
||||
log_level = regex(r" (.+?) ", 0, 1)
|
||||
source = regex(r"\[([A-Za-z_]+)\]", 0, 1)
|
||||
messsage = ps.any_char.until(ps.peek(timestamp) | ps.eof)
|
||||
|
||||
|
||||
parse_details = regex(r".*", re.MULTILINE | re.DOTALL)
|
||||
parse_sections = seq(
|
||||
header=parse_header,
|
||||
test_output=parse_test_output,
|
||||
post_test=parse_post_test,
|
||||
report=parse_report,
|
||||
summary=parse_summary,
|
||||
details=parse_details,
|
||||
)
|
||||
parse_lines = seq(
|
||||
ts=timestamp,
|
||||
level=log_level,
|
||||
src=source,
|
||||
msg=messsage.map(lambda x: "".join(x).strip()),
|
||||
).many()
|
||||
|
||||
|
||||
class Config(dict[str, str]):
|
||||
def __init__(self):
|
||||
self.dict = dotenv_values(".env")
|
||||
|
||||
def __getitem__(self, key: str, /) -> str:
|
||||
try:
|
||||
return self.dict.__getitem__(key)
|
||||
except KeyError:
|
||||
return os.environ[key]
|
||||
|
||||
def __setitem__(self, _key: str, _value: str, /):
|
||||
raise NotImplementedError("Config is read-only")
|
||||
|
||||
def __delitem__(self, _: str, /):
|
||||
raise NotImplementedError("Config is read-only")
|
||||
|
||||
def __iter__(self):
|
||||
return iter(self.dict)
|
||||
|
||||
def __len__(self):
|
||||
return len(self.dict)
|
||||
|
||||
def __repr__(self):
|
||||
return self.dict.__repr__()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
config = Config()
|
||||
with Path(config["LOGFILE"]).open() as f:
|
||||
log = f.read()
|
||||
sections = parse_sections.parse(log)
|
||||
lines = parse_lines.parse(sections["test_output"])
|
||||
ic(lines)
|
2
ise/reset-ise-passwd/.gitignore
vendored
Normal file
2
ise/reset-ise-passwd/.gitignore
vendored
Normal file
|
@ -0,0 +1,2 @@
|
|||
.venv
|
||||
.ruff_cache
|
|
@ -6,7 +6,7 @@ pkgs.mkShell {
|
|||
python-pkgs.pexpect
|
||||
python-pkgs.icecream
|
||||
python-pkgs.mypy
|
||||
python-pkgs.ruff
|
||||
# python-pkgs.ruff
|
||||
]))
|
||||
pkgs.openssh
|
||||
];
|
Loading…
Add table
Reference in a new issue