Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Test improvements #18

Merged
merged 44 commits into from
Jan 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
74ddc0c
try to figure out why desktop isn't running
RebeccaMahany Jan 22, 2024
27f8a6d
Add flare test
RebeccaMahany Jan 22, 2024
904b51b
Check out permissions in root dir
RebeccaMahany Jan 22, 2024
67e75cc
Fix drv name
RebeccaMahany Jan 22, 2024
7895297
Fix grep
RebeccaMahany Jan 22, 2024
6434800
Strip launcher path
RebeccaMahany Jan 22, 2024
438027c
Fix launcher path, again
RebeccaMahany Jan 22, 2024
51631c6
figure out why path is wrong
RebeccaMahany Jan 22, 2024
e901e63
Fix path
RebeccaMahany Jan 22, 2024
7fc9094
Get actual filename for flare
RebeccaMahany Jan 22, 2024
5e5d5b7
Set more launcher settings
RebeccaMahany Jan 22, 2024
70ea15e
Flare path
RebeccaMahany Jan 22, 2024
fbab234
Don't configure anything else for now
RebeccaMahany Jan 22, 2024
82cdc2c
Try another location for flare
RebeccaMahany Jan 22, 2024
abe0d7c
Try configuring launcher again
RebeccaMahany Jan 22, 2024
45dbd1f
Skip some waiting for now
RebeccaMahany Jan 22, 2024
5dffca3
Default root directory
RebeccaMahany Jan 22, 2024
fc630f2
Basics of mock k2 server for test
RebeccaMahany Jan 23, 2024
84bc561
Try python server for mock k2 server
RebeccaMahany Jan 23, 2024
54f7101
Add version endpoint, restart on failure
RebeccaMahany Jan 23, 2024
c335a24
Fix server bind
RebeccaMahany Jan 23, 2024
1c7a962
Fix version endpoint, check for port open and test mock server with curl
RebeccaMahany Jan 23, 2024
254de46
Check if mock k2 server is reachable
RebeccaMahany Jan 23, 2024
d15411c
what
RebeccaMahany Jan 23, 2024
0ae57dd
Try extraHosts again, see what nc has to say
RebeccaMahany Jan 23, 2024
6569652
Run nc before failing curl
RebeccaMahany Jan 23, 2024
c8f13e3
try more stuff
RebeccaMahany Jan 23, 2024
2845dfb
Try disabling firewall on one node
RebeccaMahany Jan 24, 2024
361e1a6
can we reach k2server if nginx is running
RebeccaMahany Jan 24, 2024
38ede5b
still works if we change the virtual host server name?
RebeccaMahany Jan 24, 2024
ec504ed
Fix initial server check
RebeccaMahany Jan 24, 2024
4f9c770
uwsgi maybe
RebeccaMahany Jan 24, 2024
845b471
just...run the mock server on the same node
RebeccaMahany Jan 24, 2024
d83b1fa
Reformat, fix some api issues
RebeccaMahany Jan 24, 2024
09b4279
Document mock server a little bit
RebeccaMahany Jan 24, 2024
1a69f0a
Actually return a jsonrpc response
RebeccaMahany Jan 24, 2024
f9e8e0c
Try setting http-timeout to avoid server closed idle connection err
RebeccaMahany Jan 24, 2024
6fe67b8
remove troubleshooting, hope for desktop
RebeccaMahany Jan 24, 2024
f03cd21
just wait to see if desktop shows up
RebeccaMahany Jan 24, 2024
88c60e8
take flare at very end, more screenshots
RebeccaMahany Jan 24, 2024
25e3e38
don't time out
RebeccaMahany Jan 24, 2024
91438aa
Actually enable desktop this time
RebeccaMahany Jan 24, 2024
89a79d0
Tidy up tests a bit
RebeccaMahany Jan 24, 2024
832f3ef
Add back window waits
RebeccaMahany Jan 24, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,8 @@ indent_size = 2
[*.yml]
indent_style = space
indent_size = 2

# python files: 4 spaces for indents
[*.py]
indent_style = space
indent_size = 4
8 changes: 8 additions & 0 deletions .github/workflows/validate.yml
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,14 @@ jobs:
path: ${{ steps.test-derivation.outputs.drvpath }}/test-*.png
retention-days: 1

- name: upload test flare
uses: actions/upload-artifact@v4
if: always()
with:
name: test-flare
path: ${{ steps.test-derivation.outputs.drvpath }}/kolide_agent_flare_report_*.zip
retention-days: 1

- name: show flake output attributes
run: nix flake show --impure

Expand Down
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,3 +81,8 @@ Then start the `kolide-launcher.service` service.
[NixOS tests](https://nixos.org/manual/nixos/stable/index.html#sec-nixos-tests)
live in the [./tests](./tests) directory and are included via flake checks.
They are currently intended to run in CI only.

#### Running the mock K2 server

To run the mock K2 server locally for testing purposes, you can run
`python3 -m flask --app k2server run` from the `tests` directory.
45 changes: 32 additions & 13 deletions modules/kolide-launcher/default.nix
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
flake: { config, lib, pkgs, ... }:

let
inherit (lib) types mkEnableOption mkOption mkIf;
inherit (lib) types mkEnableOption mkOption mkIf optional strings;
inherit (flake.packages.x86_64-linux) kolide-launcher;
cfg = config.services.kolide-launcher;
in
Expand Down Expand Up @@ -62,6 +62,22 @@ in
Initial autoupdater subprocess delay.
'';
};

insecureTransport = mkOption {
type = types.bool;
default = false;
description = ''
Do not use TLS for transport layer.
'';
};

insecureTLS = mkOption {
type = types.bool;
default = false;
description = ''
Do not verify TLS certs for outgoing connections.
'';
};
};

config = mkIf cfg.enable {
Expand All @@ -79,18 +95,21 @@ in
# module. So, until we have a better option, we give the kolide-launcher unit access to the symlinks
# in `/run/current-system/sw/bin` and other likely locations that will allow it to find software inside the Nix store.
Environment = "PATH=/run/wrappers/bin:/bin:/sbin:/nix/var/nix/profiles/default/bin:/run/current-system/sw/bin";
ExecStart = ''
${flake.packages.x86_64-linux.kolide-launcher}/bin/launcher \
--hostname ${cfg.kolideHostname} \
--root_directory ${cfg.rootDirectory} \
--osqueryd_path ${flake.packages.x86_64-linux.kolide-launcher}/bin/osqueryd \
--enroll_secret_path ${cfg.enrollSecretDirectory}/secret \
--update_channel ${cfg.updateChannel} \
--transport jsonrpc \
--autoupdate \
--autoupdate_interval ${cfg.autoupdateInterval} \
--autoupdater_initial_delay ${cfg.autoupdaterInitialDelay}
'';
ExecStart = strings.concatStringsSep " " ([
"${flake.packages.x86_64-linux.kolide-launcher}/bin/launcher"
"--hostname ${cfg.kolideHostname}"
"--root_directory ${cfg.rootDirectory}"
"--osqueryd_path ${flake.packages.x86_64-linux.kolide-launcher}/bin/osqueryd"
"--enroll_secret_path ${cfg.enrollSecretDirectory}/secret"
"--update_channel ${cfg.updateChannel}"
"--transport jsonrpc"
"--autoupdate"
"--autoupdate_interval ${cfg.autoupdateInterval}"
"--autoupdater_initial_delay ${cfg.autoupdaterInitialDelay}"
]
++ optional cfg.insecureTransport "--insecure_transport"
++ optional cfg.insecureTLS "--insecure"
);
Restart = "on-failure";
RestartSec = 3;
};
Expand Down
1 change: 1 addition & 0 deletions tests/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
__pycache__
87 changes: 87 additions & 0 deletions tests/k2server.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
#!/usr/bin/env python3
import json
from flask import Flask, jsonify, request, Response

application = Flask(__name__)
agent_flags_hash = "8c3503bd-c9f7-4503-ba8e-a51215e3e565"

# Device Server: JSONRPC endpoint
@application.route("/", methods=['POST'])
def jsonrpc():
# Check `method` param: RequestEnrollment and RequestConfig require specific responses
req_body = request.get_json()
if req_body["method"] == "RequestEnrollment":
return jsonify({
"result": {
"node_key": "abd",
"node_invalid": False
},
"error": None,
"id": 0
})
elif req_body["method"] == "RequestConfig":
return jsonify({
"result": {
"config": json.dumps({
"options": {
"audit_allow_config": False,
"audit_allow_fim_events": False,
"audit_allow_process_events": False,
"audit_allow_fork_process_events": False,
"audit_allow_selinux_events": False,
"audit_allow_sockets": False,
"audit_allow_user_events": False,
"disable_audit": False,
"disable_events": False,
"enable_file_events": False,
"events_max": 10000,
"enable_bpf_events": False,
"events_expiry": 3601,
"read_max": 52428800,
"logger_event_type": False,
"distributed_interval": 30,
"schedule_epoch": "1705518221"
}
}),
"node_invalid": False
},
"error": None,
"id": 0
})
else:
return jsonify({
"result": {
"node_invalid": False
},
"error": None,
"id": 0
})

# Control server: get challenge
@application.route("/api/agent/config", methods=['GET'])
def challenge():
return Response(response='1676065364', status=200, mimetype='application/octet-stream')

# Control server: get subsystems and hashes
@application.route("/api/agent/config", methods=['POST'])
def subsystems():
return jsonify({
"token": "4223b8d9-3d29-4ec9-ba18-957650cbeff0",
"config": {
"agent_flags": agent_flags_hash
}
})

# Control server: get subsystem
@application.route("/api/agent/object/<hash>", methods=['GET'])
def get_subsystem(hash):
if hash != agent_flags_hash:
return '', 404
return jsonify({"desktop_enabled_v1": "enabled"})

# Version endpoint
@application.route("/version", methods=['GET'])
def version():
r = Response(response='1', status=200, mimetype='text/html')
r.headers['Content-Type'] = 'text/html; charset=utf-8'
return r
44 changes: 42 additions & 2 deletions tests/kolide-launcher.nix
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,30 @@ pkgs.nixosTest {
hardware.pulseaudio.enable = true;

services.kolide-launcher.enable = true;
services.kolide-launcher.kolideHostname = "app.kolide.test:80";
services.kolide-launcher.insecureTransport = true;
services.kolide-launcher.insecureTLS = true;

system.stateVersion = "23.11";

# Set up mock k2 server locally
networking.extraHosts = "127.0.0.1 app.kolide.test";
services.uwsgi = {
enable = true;
plugins = [ "python3" ];
capabilities = [ "CAP_NET_BIND_SERVICE" ];
instance.type = "emperor";

instance.vassals.k2server = {
type = "normal";
module = "wsgi:application";
http = ":80";
http-timeout = 30;
cap = "net_bind_service";
pythonPackages = self: [ self.flask ];
chdir = pkgs.writeTextDir "wsgi.py" (builtins.readFile ./k2server.py);
};
};
};

enableOCR = true;
Expand All @@ -54,6 +77,11 @@ pkgs.nixosTest {
if "${ci}":
machine.start()

with subtest("mock K2 server starts up"):
machine.wait_for_unit("network-online.target")
machine.wait_for_unit("uwsgi.service")
machine.wait_until_succeeds("curl --fail http://app.kolide.test/version", timeout=60)

with subtest("log in to MATE"):
machine.wait_for_unit("display-manager.service", timeout=120)
machine.wait_for_file("${xauthority}")
Expand All @@ -74,9 +102,9 @@ pkgs.nixosTest {
with subtest("launcher service runs and is set up correctly"):
machine.systemctl("stop kolide-launcher.service")
machine.systemctl("start kolide-launcher.service")
machine.wait_for_unit("kolide-launcher.service", timeout=120)
machine.wait_for_unit("kolide-launcher.service", timeout=60)
machine.wait_for_file("/var/kolide-k2/k2device.kolide.com/debug.json")
machine.sleep(60)
machine.sleep(30)
machine.screenshot("test-screen2.png")

with subtest("osquery runs"):
Expand All @@ -88,6 +116,18 @@ pkgs.nixosTest {
machine.wait_for_file("/var/kolide-k2/k2device.kolide.com/menu.json")
machine.screenshot("test-screen4.png")

machine.wait_until_succeeds("pgrep -U ${uid} launcher", timeout=120)
machine.screenshot("test-screen5.png")

with subtest("launcher flare"):
_, launcher_find_stdout = machine.execute("ls /nix/store | grep kolide-launcher-")
machine.execute("/nix/store/" + launcher_find_stdout.strip() + "/bin/launcher flare --save local")

# copy_from_vm can't take a wildcard path, so find the exact path before copying
_, flare_ls_out = machine.execute("ls ./kolide_agent_flare_report_*.zip")
flare_path = "./" + flare_ls_out.strip()
machine.copy_from_vm(flare_path, "./")

machine.shutdown()
'';
}
Loading