First version
This commit is contained in:
commit
243e92a9dd
84 files changed
+4012
No files matched your search
Executable
+123
@@ -0,0 +1,123 @@
|
||||
#!/bin/bash
|
||||
# Runs inside the VM as root. Checks every feature of the Ansible playbooks.
|
||||
pass=0; fail=0
|
||||
c() { # c "description" command...
|
||||
local d=$1; shift
|
||||
if eval "$@" >/dev/null 2>&1; then echo "PASS $d"; pass=$((pass+1)); else echo "FAIL $d"; fail=$((fail+1)); fi
|
||||
}
|
||||
as_team() { runuser -u team -- bash -c "$1"; }
|
||||
section() { echo; echo "== $1"; }
|
||||
|
||||
section "accounts.yml / finish.yml"
|
||||
c "team is logged in automatically on the screen" "loginctl list-sessions --no-legend | grep -q 'team seat0'"
|
||||
c "team is not in the sudo group" "! id -nG team | grep -qw sudo"
|
||||
c "team is not in the lpadmin group" "! id -nG team | grep -qw lpadmin"
|
||||
c "icpc is in the sudo group" "id -nG icpc | grep -qw sudo"
|
||||
c "root password is locked" "passwd -S root | grep -q ' L '"
|
||||
c "sudo rule of vscode-extension-install removed" "[ ! -e /etc/sudoers.d/vscode-extension-install ]"
|
||||
c "vscode-extension-install not started at login" "grep -q '^Hidden=true' /etc/xdg/autostart/vscode-extension-install.desktop"
|
||||
c "VS Code extensions mounted for team at boot" "systemctl is-active -q team-vscode-extensions && findmnt /home/team/.vscode/extensions"
|
||||
c "boot menu: superuser and password" "grep -q 'set superusers=\"admin\"' /boot/grub/grub.cfg && grep -q password_pbkdf2 /boot/grub/grub.cfg"
|
||||
c "boot menu: normal entries unrestricted" "grep -q -- '--unrestricted' /boot/grub/grub.cfg"
|
||||
c "boot menu: no recovery entries" "! grep -q recovery /boot/grub/grub.cfg"
|
||||
c "boot menu password file is root only" "[ \$(stat -c %a /etc/grub.d/01_acpc_password) = 700 ]"
|
||||
c "SSH settings of the build removed" "[ ! -e /etc/ssh/sshd_config.d/00-build.conf ]"
|
||||
|
||||
section "languages.yml"
|
||||
c "gcc-15 15.2.0" "[ \$(gcc-15 -dumpfullversion) = 15.2.0 ]"
|
||||
c "g++-15 15.2.0" "[ \$(g++-15 -dumpfullversion) = 15.2.0 ]"
|
||||
c "java 25.0.4.1" "java -version 2>&1 | grep -q '\"25.0.4.1\"'"
|
||||
c "javac 25.0.4.1" "[ \"\$(javac -version 2>&1)\" = 'javac 25.0.4.1' ]"
|
||||
c "PyPy 7.3.23 / Python 3.11.15" "pypy3 -c 'import sys; assert sys.pypy_version_info[:3]==(7,3,23) and sys.version_info[:3]==(3,11,15)'"
|
||||
c "Java packages held at 25.0.4.1" "apt-mark showhold | grep -q openjdk-25-jdk-headless"
|
||||
c "compilec uses the Kattis command" "grep -q 'gcc-15 -g -O2 -o a.out -std=gnu23 -static \"\$@\" -lm' /usr/local/bin/compilec"
|
||||
c "compilecpp uses the Kattis command" "grep -q 'g++-15 -g -O2 -o a.out -std=gnu++23 -static -lrt -Wl,--whole-archive -lpthread -Wl,--no-whole-archive' /usr/local/bin/compilecpp"
|
||||
c "compilejava uses the Kattis command" "grep -q \"javac -encoding UTF-8 -sourcepath . -cp './\\*' -d .\" /usr/local/bin/compilejava"
|
||||
c "runjava uses the Kattis options" "grep -q 'UseSerialGC -Xss64m -XX:TieredStopAtLevel=1 -XX:ActiveProcessorCount=2' /usr/local/bin/runjava"
|
||||
c "runpython3 uses pypy3" "grep -q 'exec pypy3' /usr/local/bin/runpython3"
|
||||
c "compilegcc and compileg++ are other names" "[ \$(readlink /usr/local/bin/compilegcc) = /usr/local/bin/compilec ] && [ \$(readlink /usr/local/bin/compileg++) = /usr/local/bin/compilecpp ]"
|
||||
c "technical notes are the ACPC 2026 ones" "pdftotext /usr/share/doc/icpc/TechNotes.pdf - | grep -q 'Atlantic Canadian Programming Competition 2026'"
|
||||
|
||||
section "firefox.yml"
|
||||
P=/usr/lib/firefox/distribution/policies.json
|
||||
c "home page is the contest" "python3 -c \"import json;p=json.load(open('$P'))['policies'];assert p['Homepage']['URL']=='https://atlantic-canada26.kattis.com' and p['Homepage']['Locked']\""
|
||||
c "contest, offline help and documentation bookmarks" "python3 -c \"import json;p=json.load(open('$P'))['policies'];assert [b['Title'] for b in p['Bookmarks']]==['Contest','Problems','Standings','Contest Help (offline)','Language Documentation','Technical Notes'];assert p['Bookmarks'][3]['URL']=='file:///usr/share/doc/acpc/help/index.html'\""
|
||||
c "encrypted client hello off (locked)" "python3 -c \"import json;p=json.load(open('$P'))['policies']['Preferences'];assert p['network.dns.echconfig.enabled']=={'Value':False,'Status':'locked'}\""
|
||||
c "extension installs blocked" "python3 -c \"import json;p=json.load(open('$P'))['policies'];assert p['ExtensionSettings']['*']['installation_mode']=='blocked'\""
|
||||
c "about:config blocked" "python3 -c \"import json;p=json.load(open('$P'))['policies'];assert p['BlockAboutConfig'] is True\""
|
||||
|
||||
section "desktop.yml"
|
||||
c "World Finals menu entries removed" "! ls /usr/share/applications/{ccs,scoreboard,problems,ccsdocs,judgingnotes}.desktop"
|
||||
c "Contest menu: Contest, Problems, Standings and offline help" "ls /usr/share/applications/acpc-{contest,problems,standings,help}.desktop"
|
||||
c "Documentation menu entry named Language Documentation" "grep -q '^Name=Language Documentation' /usr/share/applications/devdocs.desktop"
|
||||
c "submit points to Kattis" "as_team 'submit' | grep -q 'This contest runs on Kattis'"
|
||||
c "pc2submit points to Kattis" "as_team 'pc2submit' | grep -q 'This contest runs on Kattis'"
|
||||
c "Kotlin compile/run commands removed" "[ ! -e /usr/local/bin/compilekotlin ] && [ ! -e /usr/local/bin/runkotlin ]"
|
||||
c "JetBrains agreement answered for team" "grep -rq eua_accepted_version /home/team/.java/.userPrefs/jetbrains/"
|
||||
c "JetBrains data sharing declined for team" "grep -q 'rsch.send.usage.stat:1.1:0' /home/team/.local/share/JetBrains/consentOptions/accepted"
|
||||
c "same answers in /etc/skel" "grep -rq eua_accepted_version /etc/skel/.java/.userPrefs/jetbrains/ && [ -f /etc/skel/.local/share/JetBrains/consentOptions/accepted ]"
|
||||
c "PyCharm: PyPy declared and used by default" "grep -q '/usr/local/bin/pypy3' /home/team/.config/JetBrains/PyCharm*/options/jdk.table.xml && grep -q 'PyPy 3.11' /home/team/.config/JetBrains/PyCharm*/options/project.default.xml"
|
||||
c "CLion, IntelliJ IDEA, PyCharm trust /home/team" "[ \$(grep -l '/home/team' /home/team/.config/JetBrains/*/options/trusted-paths.xml | wc -l) = 3 ]"
|
||||
c "same JetBrains settings in /etc/skel" "[ \$(ls /etc/skel/.config/JetBrains/*/options/trusted-paths.xml | wc -l) = 3 ]"
|
||||
c "Eclipse runs on Java 25.0.4.1" "grep -qx '/usr/lib/jvm/java-25-openjdk-amd64/bin/java' /opt/eclipse/eclipse.ini"
|
||||
c "Geany C build uses the contest compiler driver" "grep -q '^FT_01_CM=acpc-gcc' /usr/share/geany/filedefs/filetypes.c"
|
||||
c "Geany C++ build uses the contest compiler driver" "grep -q '^FT_01_CM=acpc-g++' /usr/share/geany/filedefs/filetypes.cpp"
|
||||
c "Geany runs Python with PyPy" "grep -q '^EX_00_CM=pypy3' /usr/share/geany/filedefs/filetypes.python"
|
||||
c "VS Code uses PyPy for Python" "grep -q '/usr/local/bin/pypy3' /home/team/.config/Code/User/settings.json"
|
||||
|
||||
c "Geany Java uses contest compilation and VM options" "grep -q '^FT_01_CM=compilejava' /usr/share/geany/filedefs/filetypes.java && grep -q '^EX_00_CM=runjava' /usr/share/geany/filedefs/filetypes.java"
|
||||
c "CLion C and C++ toolchain drivers" "grep -q 'customCCompilerPath' /home/team/.config/JetBrains/CLion*/options/linux/toolchains.xml && grep -q 'customCXXCompilerPath' /home/team/.config/JetBrains/CLion*/options/linux/toolchains.xml"
|
||||
c "CLion Python defaults to PyPy" "grep -q /usr/local/bin/pypy3 /home/team/.config/JetBrains/CLion*/options/jdk.table.xml"
|
||||
c "IntelliJ Java SDK and VM options" "grep -q java-25-openjdk /home/team/.config/JetBrains/IntelliJIdea*/options/jdk.table.xml && grep -q UseSerialGC /home/team/.config/JetBrains/IntelliJIdea*/options/project.default.xml"
|
||||
c "CodeBlocks C and C++ compiler profile" "grep -q acpc-gcc /home/team/.config/codeblocks/default.conf && grep -q acpc-g++ /home/team/.config/codeblocks/default.conf"
|
||||
c "VS Code contest build actions and F6 shortcut" "grep -q acpc-solution /home/team/.config/Code/User/tasks.json && grep -q f6 /home/team/.config/Code/User/keybindings.json"
|
||||
c "Eclipse menu initializes the contest workspace" "grep -q '^Exec=/usr/local/bin/acpc-eclipse' /usr/share/applications/Eclipse.desktop"
|
||||
c "Eclipse PyDev uses PyPy without changing Java/CDT build preferences" "grep -q /usr/local/bin/pypy3 /home/team/eclipse-workspace/.metadata/.plugins/org.eclipse.core.runtime/.settings/org.python.pydev.prefs && grep -qx CHECK_PREFERRED_PYDEV_SETTINGS=false /home/team/eclipse-workspace/.metadata/.plugins/org.eclipse.core.runtime/.settings/org.python.pydev.prefs"
|
||||
c "IDE profiles restored by reset from skel" "test -f /etc/skel/.config/codeblocks/default.conf && test -f /etc/skel/.config/Code/User/tasks.json && test -f /etc/skel/eclipse-workspace/.metadata/.plugins/org.eclipse.debug.core/.launches/ACPC\ Build\ and\ run.launch"
|
||||
|
||||
section "docs.yml"
|
||||
c "offline help is installed, root-owned and readable by team" "[ \"\$(stat -c '%U:%G:%a' /usr/share/doc/acpc/help/index.html)\" = root:root:644 ] && as_team 'test -r /usr/share/doc/acpc/help/index.html'"
|
||||
c "offline help menu opens the local document" "grep -qx 'Exec=firefox file:///usr/share/doc/acpc/help/index.html' /usr/share/applications/acpc-help.desktop"
|
||||
c "DevDocs runs" "systemctl is-active -q container-devdocs && curl -sk -o /dev/null https://devdocs/"
|
||||
c "DevDocs has exactly C, C++, OpenJDK 25, Python 3.11" "[ \"\$(podman exec devdocs ls public/docs | tr '\n' ' ')\" = 'c cpp docs.json openjdk~25 python~3.11 ' ]"
|
||||
c "Kotlin gone from the compiled list" "! podman exec devdocs sh -c 'grep -q kotlin public/assets/docs-*.js'"
|
||||
c "no 'must be loaded from devdocs.io' notice" "podman exec devdocs sh -c 'grep -q production_host:\\\"devdocs\\\" public/assets/application-*.js'"
|
||||
|
||||
section "firewall.yml"
|
||||
c "firewall, proxy and DNS filter running" "systemctl is-active -q firewall contest-proxy contest-dns"
|
||||
c "test_firewall.sh: 15 OK, no problem (as team)" "[ \$(as_team /test_firewall.sh | grep -c '^OK') = 15 ]"
|
||||
c "web egress only for the proxy account" "nft list chain inet filter output | grep -q \"skuid \$(id -u contest-proxy) tcp dport 443 accept\""
|
||||
c "DNS egress only for the proxy account" "nft list chain inet filter output | grep -q \"skuid \$(id -u contest-proxy) ip daddr 1.1.1.1 udp dport 53\""
|
||||
c "NTP egress only for chrony" "nft list chain inet filter output | grep -q \"skuid \$(id -u _chrony) ip daddr @ntp_ips udp dport 123 accept\""
|
||||
c "incoming connections dropped (policy drop)" "nft list chain inet filter input | grep -q 'policy drop'"
|
||||
c "resolv.conf points to the DNS filter" "[ \"\$(cat /etc/resolv.conf)\" = 'nameserver 127.0.0.1' ]"
|
||||
c "open.kattis.com in /etc/hosts" "grep -q 'open.kattis.com' /etc/hosts"
|
||||
c "clock synchronized by chrony" "chronyc -n sources | grep -q '^\\^\\*'"
|
||||
c "chrony does not write the hardware clock" "! grep -q '^rtcsync' /etc/chrony/chrony.conf"
|
||||
c "Ubuntu NTS sources disabled" "[ ! -e /etc/chrony/sources.d/ubuntu-ntp-pools.sources ]"
|
||||
c "clock fallback timer enabled" "systemctl is-enabled -q time_from_contest.timer"
|
||||
c "time zone America/Moncton" "[ \$(readlink -f /etc/localtime) = /usr/share/zoneinfo/America/Moncton ]"
|
||||
|
||||
section "lockdown.yml"
|
||||
c "no local AI models in the JetBrains IDEs" "[ -z \"\$(find /opt -name 'full-line-model-*' -o -name 'full-line-native-server-*')\" ]"
|
||||
c "USBGuard running, rejects new devices" "systemctl is-active -q usbguard && grep -q '^ImplicitPolicyTarget=reject' /etc/usbguard/usbguard-daemon.conf && grep -q '^PresentDevicePolicy=allow' /etc/usbguard/usbguard-daemon.conf"
|
||||
c "polkit: removable media refused to teams" "[ -f /etc/polkit-1/rules.d/10-acpc-no-removable-media.rules ]"
|
||||
c "polkit: network changes refused to teams" "[ -f /etc/polkit-1/rules.d/10-acpc-no-network-changes.rules ]"
|
||||
c "polkit: restart/power off refused to teams" "[ -f /etc/polkit-1/rules.d/10-acpc-no-power-actions.rules ]"
|
||||
c "udev: no direct access to phones" "[ -f /etc/udev/rules.d/72-acpc-no-phone-access.rules ]"
|
||||
c "team cannot reboot" "! systemd-run --machine=team@ --user --wait --pipe --quiet systemctl reboot"
|
||||
c "team cannot change the network" "systemd-run --machine=team@ --user --wait --pipe --quiet nmcli general permissions | grep -q 'network-control *no'"
|
||||
c "Ctrl+Alt+Del masked" "[ \$(systemctl is-enabled ctrl-alt-del.target 2>&1) = masked ]"
|
||||
c "SysRq off" "[ \$(cat /proc/sys/kernel/sysrq) = 0 ]"
|
||||
c "power/reboot keys ignored" "grep -q '^HandlePowerKey=ignore' /etc/systemd/logind.conf.d/90-acpc-keys.conf"
|
||||
c "desktop waits for the clock" "systemctl is-enabled -q wait-for-time"
|
||||
c "automatic updates masked" "[ \"\$(systemctl is-enabled apt-daily.timer apt-daily-upgrade.timer unattended-upgrades 2>&1 | sort -u)\" = masked ]"
|
||||
c "contest-restrictions installed, root only" "[ \$(stat -c %a /usr/local/sbin/contest-restrictions) = 700 ]"
|
||||
c "contest-restrictions status: all on" "[ \$(contest-restrictions status | grep -c ' on\$') = 3 ]"
|
||||
c "banner service running (root)" "systemctl is-active -q contest-restrictions-warning"
|
||||
c "/etc/contest-restrictions root only" "[ \$(stat -c %a /etc/contest-restrictions) = 700 ]"
|
||||
c "admin scripts unreadable by team" "! as_team 'cat /disable_firewall.sh /usr/local/sbin/contest-restrictions /reset_team_home.sh'"
|
||||
c "reset script installed" "[ -x /reset_team_home.sh ]"
|
||||
|
||||
echo
|
||||
echo "$pass passed, $fail failed"
|
||||
Reference in new issue
Block a user