From acc5d0b151fe5e2b75769d96553e0c10edb35712 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 12 Jun 2025 05:59:23 +0000 Subject: [PATCH 1/6] Initial plan for issue From 8b023b4b0f21545d1bacb9f1d6549e9e208175a7 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 12 Jun 2025 06:02:55 +0000 Subject: [PATCH 2/6] Initial analysis: identify missing test coverage for HMAC plugin Co-authored-by: GrantBirki <23362539+GrantBirki@users.noreply.github.com> --- .bundle/config | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.bundle/config b/.bundle/config index 0146a1ce..f9263841 100644 --- a/.bundle/config +++ b/.bundle/config @@ -1,7 +1,8 @@ --- BUNDLE_BIN: "bin" -BUNDLE_PATH: "vendor/gems" +BUNDLE_PATH: "/home/runner/work/hooks/hooks/vendor/bundle" BUNDLE_CACHE_PATH: "vendor/cache" BUNDLE_CACHE_ALL: "true" BUNDLE_SPECIFIC_PLATFORM: "true" BUNDLE_NO_INSTALL: "true" +BUNDLE_DEPLOYMENT: "true" From 2c2703296fd8e374b0acfa9fb5f40a1bca2a408c Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 12 Jun 2025 06:08:52 +0000 Subject: [PATCH 3/6] Complete HMAC test coverage by implementing missing test cases Co-authored-by: GrantBirki <23362539+GrantBirki@users.noreply.github.com> --- for grouping | 79 ++++++ spec/unit/lib/hooks/plugins/auth/hmac_spec.rb | 26 +- tdout on a dedicated line | 258 ++++++++++++++++++ 3 files changed, 355 insertions(+), 8 deletions(-) create mode 100644 for grouping create mode 100644 tdout on a dedicated line diff --git a/for grouping b/for grouping new file mode 100644 index 00000000..f70d8e25 --- /dev/null +++ b/for grouping @@ -0,0 +1,79 @@ +diff --git a/spec/unit/lib/hooks/plugins/auth/hmac_spec.rb b/spec/unit/lib/hooks/plugins/auth/hmac_spec.rb +index 9e8b01c..fa12174 100644 +--- a/spec/unit/lib/hooks/plugins/auth/hmac_spec.rb ++++ b/spec/unit/lib/hooks/plugins/auth/hmac_spec.rb +@@ -70,7 +70,8 @@ describe Hooks::Plugins::Auth::HMAC do + auth: { + header: header, + algorithm: "sha256", +- format: "signature_only" ++ format: "signature_only", ++ secret_env_key: "HMAC_TEST_SECRET" + } + } + end +@@ -78,7 +79,7 @@ describe Hooks::Plugins::Auth::HMAC do + let(:headers) { { header => signature } } +  + it "returns true for a valid hash-only signature" do +- # TODO ++ expect(valid_with(headers:, config:)).to be true + end +  + it "returns false for an invalid hash-only signature" do +@@ -104,13 +105,14 @@ describe Hooks::Plugins::Auth::HMAC do + format: "version=signature", + version_prefix: "v0", + payload_template: payload_template, +- timestamp_tolerance: 300 ++ timestamp_tolerance: 300, ++ secret_env_key: "HMAC_TEST_SECRET" + } + } + end +  + it "returns true for a valid versioned signature with valid timestamp" do +- # TODO ++ expect(valid_with(headers:, config:)).to be true + end +  + it "returns false for an expired timestamp" do +@@ -153,10 +155,10 @@ describe Hooks::Plugins::Auth::HMAC do +  + context "with missing config values" do + let(:headers) { { "X-Signature" => "sha256=" + OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new("sha256"), secret, payload) } } +- let(:config) { {} } ++ let(:config) { { auth: { secret_env_key: "HMAC_TEST_SECRET" } } } +  + it "uses defaults and validates correctly" do +- # TODO ++ expect(valid_with(headers:, config:)).to be true + end + end +  +@@ -404,7 +406,8 @@ describe Hooks::Plugins::Auth::HMAC do + format: "version=signature", + version_prefix: "v0", + payload_template: "v0:{timestamp}:{body}", +- timestamp_tolerance: 300 ++ timestamp_tolerance: 300, ++ secret_env_key: "HMAC_TEST_SECRET" + } + } + end +@@ -464,7 +467,14 @@ describe Hooks::Plugins::Auth::HMAC do + end +  + it "returns true when timestamp header name case differs due to normalization" do +- # TODO ++ timestamp = Time.now.to_i.to_s ++ signing_payload = "v0:#{timestamp}:#{payload}" ++ signature = "v0=" + OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new("sha256"), secret, signing_payload) ++ ++ # Use uppercase timestamp header name in the request headers ++ headers = { header => signature, timestamp_header.upcase => timestamp } ++ ++ expect(valid_with(headers:, config: base_config)).to be true + end + end +  diff --git a/spec/unit/lib/hooks/plugins/auth/hmac_spec.rb b/spec/unit/lib/hooks/plugins/auth/hmac_spec.rb index 9e8b01c4..fa121745 100644 --- a/spec/unit/lib/hooks/plugins/auth/hmac_spec.rb +++ b/spec/unit/lib/hooks/plugins/auth/hmac_spec.rb @@ -70,7 +70,8 @@ def valid_with(args = {}) auth: { header: header, algorithm: "sha256", - format: "signature_only" + format: "signature_only", + secret_env_key: "HMAC_TEST_SECRET" } } end @@ -78,7 +79,7 @@ def valid_with(args = {}) let(:headers) { { header => signature } } it "returns true for a valid hash-only signature" do - # TODO + expect(valid_with(headers:, config:)).to be true end it "returns false for an invalid hash-only signature" do @@ -104,13 +105,14 @@ def valid_with(args = {}) format: "version=signature", version_prefix: "v0", payload_template: payload_template, - timestamp_tolerance: 300 + timestamp_tolerance: 300, + secret_env_key: "HMAC_TEST_SECRET" } } end it "returns true for a valid versioned signature with valid timestamp" do - # TODO + expect(valid_with(headers:, config:)).to be true end it "returns false for an expired timestamp" do @@ -153,10 +155,10 @@ def valid_with(args = {}) context "with missing config values" do let(:headers) { { "X-Signature" => "sha256=" + OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new("sha256"), secret, payload) } } - let(:config) { {} } + let(:config) { { auth: { secret_env_key: "HMAC_TEST_SECRET" } } } it "uses defaults and validates correctly" do - # TODO + expect(valid_with(headers:, config:)).to be true end end @@ -404,7 +406,8 @@ def valid_with(args = {}) format: "version=signature", version_prefix: "v0", payload_template: "v0:{timestamp}:{body}", - timestamp_tolerance: 300 + timestamp_tolerance: 300, + secret_env_key: "HMAC_TEST_SECRET" } } end @@ -464,7 +467,14 @@ def valid_with(args = {}) end it "returns true when timestamp header name case differs due to normalization" do - # TODO + timestamp = Time.now.to_i.to_s + signing_payload = "v0:#{timestamp}:#{payload}" + signature = "v0=" + OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new("sha256"), secret, signing_payload) + + # Use uppercase timestamp header name in the request headers + headers = { header => signature, timestamp_header.upcase => timestamp } + + expect(valid_with(headers:, config: base_config)).to be true end end diff --git a/tdout on a dedicated line b/tdout on a dedicated line new file mode 100644 index 00000000..333a0b57 --- /dev/null +++ b/tdout on a dedicated line @@ -0,0 +1,258 @@ + + SSUUMMMMAARRYY OOFF LLEESSSS CCOOMMMMAANNDDSS + + Commands marked with * may be preceded by a number, _N. + Notes in parentheses indicate the behavior if _N is given. + A key preceded by a caret indicates the Ctrl key; thus ^K is ctrl-K. + + h H Display this help. + q :q Q :Q ZZ Exit. + --------------------------------------------------------------------------- + + MMOOVVIINNGG + + e ^E j ^N CR * Forward one line (or _N lines). + y ^Y k ^K ^P * Backward one line (or _N lines). + f ^F ^V SPACE * Forward one window (or _N lines). + b ^B ESC-v * Backward one window (or _N lines). + z * Forward one window (and set window to _N). + w * Backward one window (and set window to _N). + ESC-SPACE * Forward one window, but don't stop at end-of-file. + d ^D * Forward one half-window (and set half-window to _N). + u ^U * Backward one half-window (and set half-window to _N). + ESC-) RightArrow * Right one half screen width (or _N positions). + ESC-( LeftArrow * Left one half screen width (or _N positions). + ESC-} ^RightArrow Right to last column displayed. + ESC-{ ^LeftArrow Left to first column. + F Forward forever; like "tail -f". + ESC-F Like F but stop when search pattern is found. + r ^R ^L Repaint screen. + R Repaint screen, discarding buffered input. + --------------------------------------------------- + Default "window" is the screen height. + Default "half-window" is half of the screen height. + --------------------------------------------------------------------------- + + SSEEAARRCCHHIINNGG + + /_p_a_t_t_e_r_n * Search forward for (_N-th) matching line. + ?_p_a_t_t_e_r_n * Search backward for (_N-th) matching line. + n * Repeat previous search (for _N-th occurrence). + N * Repeat previous search in reverse direction. + ESC-n * Repeat previous search, spanning files. + ESC-N * Repeat previous search, reverse dir. & spanning files. + ESC-u Undo (toggle) search highlighting. + ESC-U Clear search highlighting. + &_p_a_t_t_e_r_n * Display only matching lines. + --------------------------------------------------- + A search pattern may begin with one or more of: + ^N or ! Search for NON-matching lines. + ^E or * Search multiple files (pass thru END OF FILE). + ^F or @ Start search at FIRST file (for /) or last file (for ?). + ^K Highlight matches, but don't move (KEEP position). + ^R Don't use REGULAR EXPRESSIONS. + ^W WRAP search if no match found. + --------------------------------------------------------------------------- + + JJUUMMPPIINNGG + + g < ESC-< * Go to first line in file (or line _N). + G > ESC-> * Go to last line in file (or line _N). + p % * Go to beginning of file (or _N percent into file). + t * Go to the (_N-th) next tag. + T * Go to the (_N-th) previous tag. + { ( [ * Find close bracket } ) ]. + } ) ] * Find open bracket { ( [. + ESC-^F _<_c_1_> _<_c_2_> * Find close bracket _<_c_2_>. + ESC-^B _<_c_1_> _<_c_2_> * Find open bracket _<_c_1_>. + --------------------------------------------------- + Each "find close bracket" command goes forward to the close bracket + matching the (_N-th) open bracket in the top line. + Each "find open bracket" command goes backward to the open bracket + matching the (_N-th) close bracket in the bottom line. + + m_<_l_e_t_t_e_r_> Mark the current top line with . + M_<_l_e_t_t_e_r_> Mark the current bottom line with . + '_<_l_e_t_t_e_r_> Go to a previously marked position. + '' Go to the previous position. + ^X^X Same as '. + ESC-M_<_l_e_t_t_e_r_> Clear a mark. + --------------------------------------------------- + A mark is any upper-case or lower-case letter. + Certain marks are predefined: + ^ means beginning of the file + $ means end of the file + --------------------------------------------------------------------------- + + CCHHAANNGGIINNGG FFIILLEESS + + :e [_f_i_l_e] Examine a new file. + ^X^V Same as :e. + :n * Examine the (_N-th) next file from the command line. + :p * Examine the (_N-th) previous file from the command line. + :x * Examine the first (or _N-th) file from the command line. + :d Delete the current file from the command line list. + = ^G :f Print current file name. + --------------------------------------------------------------------------- + + MMIISSCCEELLLLAANNEEOOUUSS CCOOMMMMAANNDDSS + + -_<_f_l_a_g_> Toggle a command line option [see OPTIONS below]. + --_<_n_a_m_e_> Toggle a command line option, by name. + __<_f_l_a_g_> Display the setting of a command line option. + ___<_n_a_m_e_> Display the setting of an option, by name. + +_c_m_d Execute the less cmd each time a new file is examined. + + !_c_o_m_m_a_n_d Execute the shell command with $SHELL. + |XX_c_o_m_m_a_n_d Pipe file between current pos & mark XX to shell command. + s _f_i_l_e Save input to a file. + v Edit the current file with $VISUAL or $EDITOR. + V Print version number of "less". + --------------------------------------------------------------------------- + + OOPPTTIIOONNSS + + Most options may be changed either on the command line, + or from within less by using the - or -- command. + Options may be given in one of two forms: either a single + character preceded by a -, or a name preceded by --. + + -? ........ --help + Display help (from command line). + -a ........ --search-skip-screen + Search skips current screen. + -A ........ --SEARCH-SKIP-SCREEN + Search starts just after target line. + -b [_N] .... --buffers=[_N] + Number of buffers. + -B ........ --auto-buffers + Don't automatically allocate buffers for pipes. + -c ........ --clear-screen + Repaint by clearing rather than scrolling. + -d ........ --dumb + Dumb terminal. + -D xx_c_o_l_o_r . --color=xx_c_o_l_o_r + Set screen colors. + -e -E .... --quit-at-eof --QUIT-AT-EOF + Quit at end of file. + -f ........ --force + Force open non-regular files. + -F ........ --quit-if-one-screen + Quit if entire file fits on first screen. + -g ........ --hilite-search + Highlight only last match for searches. + -G ........ --HILITE-SEARCH + Don't highlight any matches for searches. + -h [_N] .... --max-back-scroll=[_N] + Backward scroll limit. + -i ........ --ignore-case + Ignore case in searches that do not contain uppercase. + -I ........ --IGNORE-CASE + Ignore case in all searches. + -j [_N] .... --jump-target=[_N] + Screen position of target lines. + -J ........ --status-column + Display a status column at left edge of screen. + -k [_f_i_l_e] . --lesskey-file=[_f_i_l_e] + Use a lesskey file. + -K ........ --quit-on-intr + Exit less in response to ctrl-C. + -L ........ --no-lessopen + Ignore the LESSOPEN environment variable. + -m -M .... --long-prompt --LONG-PROMPT + Set prompt style. + -n -N .... --line-numbers --LINE-NUMBERS + Don't use line numbers. + -o [_f_i_l_e] . --log-file=[_f_i_l_e] + Copy to log file (standard input only). + -O [_f_i_l_e] . --LOG-FILE=[_f_i_l_e] + Copy to log file (unconditionally overwrite). + -p [_p_a_t_t_e_r_n] --pattern=[_p_a_t_t_e_r_n] + Start at pattern (from command line). + -P [_p_r_o_m_p_t] --prompt=[_p_r_o_m_p_t] + Define new prompt. + -q -Q .... --quiet --QUIET --silent --SILENT + Quiet the terminal bell. + -r -R .... --raw-control-chars --RAW-CONTROL-CHARS + Output "raw" control characters. + -s ........ --squeeze-blank-lines + Squeeze multiple blank lines. + -S ........ --chop-long-lines + Chop (truncate) long lines rather than wrapping. + -t [_t_a_g] .. --tag=[_t_a_g] + Find a tag. + -T [_t_a_g_s_f_i_l_e] --tag-file=[_t_a_g_s_f_i_l_e] + Use an alternate tags file. + -u -U .... --underline-special --UNDERLINE-SPECIAL + Change handling of backspaces. + -V ........ --version + Display the version number of "less". + -w ........ --hilite-unread + Highlight first new line after forward-screen. + -W ........ --HILITE-UNREAD + Highlight first new line after any forward movement. + -x [_N[,...]] --tabs=[_N[,...]] + Set tab stops. + -X ........ --no-init + Don't use termcap init/deinit strings. + -y [_N] .... --max-forw-scroll=[_N] + Forward scroll limit. + -z [_N] .... --window=[_N] + Set size of window. + -" [_c[_c]] . --quotes=[_c[_c]] + Set shell quote characters. + -~ ........ --tilde + Don't display tildes after end of file. + -# [_N] .... --shift=[_N] + Set horizontal scroll amount (0 = one half screen width). + --file-size + Automatically determine the size of the input file. + --follow-name + The F command changes files if the input file is renamed. + --incsearch + Search file as each pattern character is typed in. + --line-num-width=N + Set the width of the -N line number field to N characters. + --mouse + Enable mouse input. + --no-keypad + Don't send termcap keypad init/deinit strings. + --no-histdups + Remove duplicates from command history. + --rscroll=C + Set the character used to mark truncated lines. + --save-marks + Retain marks across invocations of less. + --status-col-width=N + Set the width of the -J status column to N characters. + --use-backslash + Subsequent options use backslash as escape char. + --use-color + Enables colored text. + --wheel-lines=N + Each click of the mouse wheel moves N lines. + + + --------------------------------------------------------------------------- + + LLIINNEE EEDDIITTIINNGG + + These keys can be used to edit text being entered + on the "command line" at the bottom of the screen. + + RightArrow ..................... ESC-l ... Move cursor right one character. + LeftArrow ...................... ESC-h ... Move cursor left one character. + ctrl-RightArrow ESC-RightArrow ESC-w ... Move cursor right one word. + ctrl-LeftArrow ESC-LeftArrow ESC-b ... Move cursor left one word. + HOME ........................... ESC-0 ... Move cursor to start of line. + END ............................ ESC-$ ... Move cursor to end of line. + BACKSPACE ................................ Delete char to left of cursor. + DELETE ......................... ESC-x ... Delete char under cursor. + ctrl-BACKSPACE ESC-BACKSPACE ........... Delete word to left of cursor. + ctrl-DELETE .... ESC-DELETE .... ESC-X ... Delete word under cursor. + ctrl-U ......... ESC (MS-DOS only) ....... Delete entire line. + UpArrow ........................ ESC-k ... Retrieve previous command line. + DownArrow ...................... ESC-j ... Retrieve next command line. + TAB ...................................... Complete filename & cycle. + SHIFT-TAB ...................... ESC-TAB Complete filename & reverse cycle. + ctrl-L ................................... Complete filename, list all. From daf13cc26e894e28253d2ffddf2bef8b4bb98edc Mon Sep 17 00:00:00 2001 From: GrantBirki Date: Thu, 12 Jun 2025 10:01:32 -0700 Subject: [PATCH 4/6] cleanup --- .bundle/config | 3 +- for grouping | 79 ------------ tdout on a dedicated line | 258 -------------------------------------- 3 files changed, 1 insertion(+), 339 deletions(-) delete mode 100644 for grouping delete mode 100644 tdout on a dedicated line diff --git a/.bundle/config b/.bundle/config index f9263841..0146a1ce 100644 --- a/.bundle/config +++ b/.bundle/config @@ -1,8 +1,7 @@ --- BUNDLE_BIN: "bin" -BUNDLE_PATH: "/home/runner/work/hooks/hooks/vendor/bundle" +BUNDLE_PATH: "vendor/gems" BUNDLE_CACHE_PATH: "vendor/cache" BUNDLE_CACHE_ALL: "true" BUNDLE_SPECIFIC_PLATFORM: "true" BUNDLE_NO_INSTALL: "true" -BUNDLE_DEPLOYMENT: "true" diff --git a/for grouping b/for grouping deleted file mode 100644 index f70d8e25..00000000 --- a/for grouping +++ /dev/null @@ -1,79 +0,0 @@ -diff --git a/spec/unit/lib/hooks/plugins/auth/hmac_spec.rb b/spec/unit/lib/hooks/plugins/auth/hmac_spec.rb -index 9e8b01c..fa12174 100644 ---- a/spec/unit/lib/hooks/plugins/auth/hmac_spec.rb -+++ b/spec/unit/lib/hooks/plugins/auth/hmac_spec.rb -@@ -70,7 +70,8 @@ describe Hooks::Plugins::Auth::HMAC do - auth: { - header: header, - algorithm: "sha256", -- format: "signature_only" -+ format: "signature_only", -+ secret_env_key: "HMAC_TEST_SECRET" - } - } - end -@@ -78,7 +79,7 @@ describe Hooks::Plugins::Auth::HMAC do - let(:headers) { { header => signature } } -  - it "returns true for a valid hash-only signature" do -- # TODO -+ expect(valid_with(headers:, config:)).to be true - end -  - it "returns false for an invalid hash-only signature" do -@@ -104,13 +105,14 @@ describe Hooks::Plugins::Auth::HMAC do - format: "version=signature", - version_prefix: "v0", - payload_template: payload_template, -- timestamp_tolerance: 300 -+ timestamp_tolerance: 300, -+ secret_env_key: "HMAC_TEST_SECRET" - } - } - end -  - it "returns true for a valid versioned signature with valid timestamp" do -- # TODO -+ expect(valid_with(headers:, config:)).to be true - end -  - it "returns false for an expired timestamp" do -@@ -153,10 +155,10 @@ describe Hooks::Plugins::Auth::HMAC do -  - context "with missing config values" do - let(:headers) { { "X-Signature" => "sha256=" + OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new("sha256"), secret, payload) } } -- let(:config) { {} } -+ let(:config) { { auth: { secret_env_key: "HMAC_TEST_SECRET" } } } -  - it "uses defaults and validates correctly" do -- # TODO -+ expect(valid_with(headers:, config:)).to be true - end - end -  -@@ -404,7 +406,8 @@ describe Hooks::Plugins::Auth::HMAC do - format: "version=signature", - version_prefix: "v0", - payload_template: "v0:{timestamp}:{body}", -- timestamp_tolerance: 300 -+ timestamp_tolerance: 300, -+ secret_env_key: "HMAC_TEST_SECRET" - } - } - end -@@ -464,7 +467,14 @@ describe Hooks::Plugins::Auth::HMAC do - end -  - it "returns true when timestamp header name case differs due to normalization" do -- # TODO -+ timestamp = Time.now.to_i.to_s -+ signing_payload = "v0:#{timestamp}:#{payload}" -+ signature = "v0=" + OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new("sha256"), secret, signing_payload) -+ -+ # Use uppercase timestamp header name in the request headers -+ headers = { header => signature, timestamp_header.upcase => timestamp } -+ -+ expect(valid_with(headers:, config: base_config)).to be true - end - end -  diff --git a/tdout on a dedicated line b/tdout on a dedicated line deleted file mode 100644 index 333a0b57..00000000 --- a/tdout on a dedicated line +++ /dev/null @@ -1,258 +0,0 @@ - - SSUUMMMMAARRYY OOFF LLEESSSS CCOOMMMMAANNDDSS - - Commands marked with * may be preceded by a number, _N. - Notes in parentheses indicate the behavior if _N is given. - A key preceded by a caret indicates the Ctrl key; thus ^K is ctrl-K. - - h H Display this help. - q :q Q :Q ZZ Exit. - --------------------------------------------------------------------------- - - MMOOVVIINNGG - - e ^E j ^N CR * Forward one line (or _N lines). - y ^Y k ^K ^P * Backward one line (or _N lines). - f ^F ^V SPACE * Forward one window (or _N lines). - b ^B ESC-v * Backward one window (or _N lines). - z * Forward one window (and set window to _N). - w * Backward one window (and set window to _N). - ESC-SPACE * Forward one window, but don't stop at end-of-file. - d ^D * Forward one half-window (and set half-window to _N). - u ^U * Backward one half-window (and set half-window to _N). - ESC-) RightArrow * Right one half screen width (or _N positions). - ESC-( LeftArrow * Left one half screen width (or _N positions). - ESC-} ^RightArrow Right to last column displayed. - ESC-{ ^LeftArrow Left to first column. - F Forward forever; like "tail -f". - ESC-F Like F but stop when search pattern is found. - r ^R ^L Repaint screen. - R Repaint screen, discarding buffered input. - --------------------------------------------------- - Default "window" is the screen height. - Default "half-window" is half of the screen height. - --------------------------------------------------------------------------- - - SSEEAARRCCHHIINNGG - - /_p_a_t_t_e_r_n * Search forward for (_N-th) matching line. - ?_p_a_t_t_e_r_n * Search backward for (_N-th) matching line. - n * Repeat previous search (for _N-th occurrence). - N * Repeat previous search in reverse direction. - ESC-n * Repeat previous search, spanning files. - ESC-N * Repeat previous search, reverse dir. & spanning files. - ESC-u Undo (toggle) search highlighting. - ESC-U Clear search highlighting. - &_p_a_t_t_e_r_n * Display only matching lines. - --------------------------------------------------- - A search pattern may begin with one or more of: - ^N or ! Search for NON-matching lines. - ^E or * Search multiple files (pass thru END OF FILE). - ^F or @ Start search at FIRST file (for /) or last file (for ?). - ^K Highlight matches, but don't move (KEEP position). - ^R Don't use REGULAR EXPRESSIONS. - ^W WRAP search if no match found. - --------------------------------------------------------------------------- - - JJUUMMPPIINNGG - - g < ESC-< * Go to first line in file (or line _N). - G > ESC-> * Go to last line in file (or line _N). - p % * Go to beginning of file (or _N percent into file). - t * Go to the (_N-th) next tag. - T * Go to the (_N-th) previous tag. - { ( [ * Find close bracket } ) ]. - } ) ] * Find open bracket { ( [. - ESC-^F _<_c_1_> _<_c_2_> * Find close bracket _<_c_2_>. - ESC-^B _<_c_1_> _<_c_2_> * Find open bracket _<_c_1_>. - --------------------------------------------------- - Each "find close bracket" command goes forward to the close bracket - matching the (_N-th) open bracket in the top line. - Each "find open bracket" command goes backward to the open bracket - matching the (_N-th) close bracket in the bottom line. - - m_<_l_e_t_t_e_r_> Mark the current top line with . - M_<_l_e_t_t_e_r_> Mark the current bottom line with . - '_<_l_e_t_t_e_r_> Go to a previously marked position. - '' Go to the previous position. - ^X^X Same as '. - ESC-M_<_l_e_t_t_e_r_> Clear a mark. - --------------------------------------------------- - A mark is any upper-case or lower-case letter. - Certain marks are predefined: - ^ means beginning of the file - $ means end of the file - --------------------------------------------------------------------------- - - CCHHAANNGGIINNGG FFIILLEESS - - :e [_f_i_l_e] Examine a new file. - ^X^V Same as :e. - :n * Examine the (_N-th) next file from the command line. - :p * Examine the (_N-th) previous file from the command line. - :x * Examine the first (or _N-th) file from the command line. - :d Delete the current file from the command line list. - = ^G :f Print current file name. - --------------------------------------------------------------------------- - - MMIISSCCEELLLLAANNEEOOUUSS CCOOMMMMAANNDDSS - - -_<_f_l_a_g_> Toggle a command line option [see OPTIONS below]. - --_<_n_a_m_e_> Toggle a command line option, by name. - __<_f_l_a_g_> Display the setting of a command line option. - ___<_n_a_m_e_> Display the setting of an option, by name. - +_c_m_d Execute the less cmd each time a new file is examined. - - !_c_o_m_m_a_n_d Execute the shell command with $SHELL. - |XX_c_o_m_m_a_n_d Pipe file between current pos & mark XX to shell command. - s _f_i_l_e Save input to a file. - v Edit the current file with $VISUAL or $EDITOR. - V Print version number of "less". - --------------------------------------------------------------------------- - - OOPPTTIIOONNSS - - Most options may be changed either on the command line, - or from within less by using the - or -- command. - Options may be given in one of two forms: either a single - character preceded by a -, or a name preceded by --. - - -? ........ --help - Display help (from command line). - -a ........ --search-skip-screen - Search skips current screen. - -A ........ --SEARCH-SKIP-SCREEN - Search starts just after target line. - -b [_N] .... --buffers=[_N] - Number of buffers. - -B ........ --auto-buffers - Don't automatically allocate buffers for pipes. - -c ........ --clear-screen - Repaint by clearing rather than scrolling. - -d ........ --dumb - Dumb terminal. - -D xx_c_o_l_o_r . --color=xx_c_o_l_o_r - Set screen colors. - -e -E .... --quit-at-eof --QUIT-AT-EOF - Quit at end of file. - -f ........ --force - Force open non-regular files. - -F ........ --quit-if-one-screen - Quit if entire file fits on first screen. - -g ........ --hilite-search - Highlight only last match for searches. - -G ........ --HILITE-SEARCH - Don't highlight any matches for searches. - -h [_N] .... --max-back-scroll=[_N] - Backward scroll limit. - -i ........ --ignore-case - Ignore case in searches that do not contain uppercase. - -I ........ --IGNORE-CASE - Ignore case in all searches. - -j [_N] .... --jump-target=[_N] - Screen position of target lines. - -J ........ --status-column - Display a status column at left edge of screen. - -k [_f_i_l_e] . --lesskey-file=[_f_i_l_e] - Use a lesskey file. - -K ........ --quit-on-intr - Exit less in response to ctrl-C. - -L ........ --no-lessopen - Ignore the LESSOPEN environment variable. - -m -M .... --long-prompt --LONG-PROMPT - Set prompt style. - -n -N .... --line-numbers --LINE-NUMBERS - Don't use line numbers. - -o [_f_i_l_e] . --log-file=[_f_i_l_e] - Copy to log file (standard input only). - -O [_f_i_l_e] . --LOG-FILE=[_f_i_l_e] - Copy to log file (unconditionally overwrite). - -p [_p_a_t_t_e_r_n] --pattern=[_p_a_t_t_e_r_n] - Start at pattern (from command line). - -P [_p_r_o_m_p_t] --prompt=[_p_r_o_m_p_t] - Define new prompt. - -q -Q .... --quiet --QUIET --silent --SILENT - Quiet the terminal bell. - -r -R .... --raw-control-chars --RAW-CONTROL-CHARS - Output "raw" control characters. - -s ........ --squeeze-blank-lines - Squeeze multiple blank lines. - -S ........ --chop-long-lines - Chop (truncate) long lines rather than wrapping. - -t [_t_a_g] .. --tag=[_t_a_g] - Find a tag. - -T [_t_a_g_s_f_i_l_e] --tag-file=[_t_a_g_s_f_i_l_e] - Use an alternate tags file. - -u -U .... --underline-special --UNDERLINE-SPECIAL - Change handling of backspaces. - -V ........ --version - Display the version number of "less". - -w ........ --hilite-unread - Highlight first new line after forward-screen. - -W ........ --HILITE-UNREAD - Highlight first new line after any forward movement. - -x [_N[,...]] --tabs=[_N[,...]] - Set tab stops. - -X ........ --no-init - Don't use termcap init/deinit strings. - -y [_N] .... --max-forw-scroll=[_N] - Forward scroll limit. - -z [_N] .... --window=[_N] - Set size of window. - -" [_c[_c]] . --quotes=[_c[_c]] - Set shell quote characters. - -~ ........ --tilde - Don't display tildes after end of file. - -# [_N] .... --shift=[_N] - Set horizontal scroll amount (0 = one half screen width). - --file-size - Automatically determine the size of the input file. - --follow-name - The F command changes files if the input file is renamed. - --incsearch - Search file as each pattern character is typed in. - --line-num-width=N - Set the width of the -N line number field to N characters. - --mouse - Enable mouse input. - --no-keypad - Don't send termcap keypad init/deinit strings. - --no-histdups - Remove duplicates from command history. - --rscroll=C - Set the character used to mark truncated lines. - --save-marks - Retain marks across invocations of less. - --status-col-width=N - Set the width of the -J status column to N characters. - --use-backslash - Subsequent options use backslash as escape char. - --use-color - Enables colored text. - --wheel-lines=N - Each click of the mouse wheel moves N lines. - - - --------------------------------------------------------------------------- - - LLIINNEE EEDDIITTIINNGG - - These keys can be used to edit text being entered - on the "command line" at the bottom of the screen. - - RightArrow ..................... ESC-l ... Move cursor right one character. - LeftArrow ...................... ESC-h ... Move cursor left one character. - ctrl-RightArrow ESC-RightArrow ESC-w ... Move cursor right one word. - ctrl-LeftArrow ESC-LeftArrow ESC-b ... Move cursor left one word. - HOME ........................... ESC-0 ... Move cursor to start of line. - END ............................ ESC-$ ... Move cursor to end of line. - BACKSPACE ................................ Delete char to left of cursor. - DELETE ......................... ESC-x ... Delete char under cursor. - ctrl-BACKSPACE ESC-BACKSPACE ........... Delete word to left of cursor. - ctrl-DELETE .... ESC-DELETE .... ESC-X ... Delete word under cursor. - ctrl-U ......... ESC (MS-DOS only) ....... Delete entire line. - UpArrow ........................ ESC-k ... Retrieve previous command line. - DownArrow ...................... ESC-j ... Retrieve next command line. - TAB ...................................... Complete filename & cycle. - SHIFT-TAB ...................... ESC-TAB Complete filename & reverse cycle. - ctrl-L ................................... Complete filename, list all. From 758016daa66ba24e115f2d64f501651251f12dd6 Mon Sep 17 00:00:00 2001 From: GrantBirki Date: Thu, 12 Jun 2025 10:11:29 -0700 Subject: [PATCH 5/6] Add missing line breaks for improved readability in Puma configuration --- spec/acceptance/config/puma.rb | 3 +++ 1 file changed, 3 insertions(+) diff --git a/spec/acceptance/config/puma.rb b/spec/acceptance/config/puma.rb index c5cb415f..6f645acc 100644 --- a/spec/acceptance/config/puma.rb +++ b/spec/acceptance/config/puma.rb @@ -4,9 +4,12 @@ require "json" bind "tcp://0.0.0.0:8080" + # single mode: https://github.com/puma/puma/blob/master/docs/deployment.md#single-vs-cluster-mode workers 0 +threads 0, 16 # the default + log_formatter do |msg| timestamp = Time.now.strftime("%Y-%m-%dT%H:%M:%S.%L%z") { From c0d0f45326083b012dbe25486c05d32ebe059841 Mon Sep 17 00:00:00 2001 From: GrantBirki Date: Thu, 12 Jun 2025 10:18:28 -0700 Subject: [PATCH 6/6] add a load test script --- script/load_test | 105 +++++++++++++++++++++ spec/acceptance/config/endpoints/hello.yml | 2 + spec/acceptance/plugins/handlers/hello.rb | 11 +++ 3 files changed, 118 insertions(+) create mode 100755 script/load_test create mode 100644 spec/acceptance/config/endpoints/hello.yml create mode 100644 spec/acceptance/plugins/handlers/hello.rb diff --git a/script/load_test b/script/load_test new file mode 100755 index 00000000..b05b6146 --- /dev/null +++ b/script/load_test @@ -0,0 +1,105 @@ +#!/usr/bin/env ruby +# frozen_string_literal: true + +require "net/http" +require "json" +require "uri" + +# Configuration +TARGET_URL = "http://0.0.0.0:8080/webhooks/hello" +REQUEST_COUNT = 10_000 # Total number of requests to send +EMPTY_JSON_BODY = "{}" + +# Parse the target URL +uri = URI.parse(TARGET_URL) + +# Initialize statistics tracking +response_times = [] +success_count = 0 +error_count = 0 + +puts "Starting load test..." +puts "Target: #{TARGET_URL}" +puts "Requests: #{REQUEST_COUNT}" +puts "Payload: #{EMPTY_JSON_BODY}" +puts "" + +# Perform the load test +REQUEST_COUNT.times do |i| + start_time = Time.now + + begin + # Create HTTP connection + http = Net::HTTP.new(uri.host, uri.port) + http.use_ssl = false if uri.scheme == "http" + + # Create POST request + request = Net::HTTP::Post.new(uri.path) + request["Content-Type"] = "application/json" + request.body = EMPTY_JSON_BODY + + # Send request and measure time + response = http.request(request) + end_time = Time.now + + response_time_ms = ((end_time - start_time) * 1000).round(2) + response_times << response_time_ms + + if response.code.to_i >= 200 && response.code.to_i < 300 + success_count += 1 + else + error_count += 1 + end + + # Progress indicator + if (i + 1) % 100 == 0 + puts "Completed #{i + 1}/#{REQUEST_COUNT} requests" + end + + rescue => e + end_time = Time.now + response_time_ms = ((end_time - start_time) * 1000).round(2) + response_times << response_time_ms + error_count += 1 + puts "Error on request #{i + 1}: #{e.message}" + end +end + +puts "" +puts "Load test completed!" +puts "" + +# Calculate statistics +if response_times.any? + sorted_times = response_times.sort + average_time = (response_times.sum / response_times.length).round(2) + min_time = sorted_times.first + max_time = sorted_times.last + median_time = if sorted_times.length.odd? + sorted_times[sorted_times.length / 2] + else + ((sorted_times[sorted_times.length / 2 - 1] + sorted_times[sorted_times.length / 2]) / 2.0).round(2) + end + + # Calculate percentiles + p95_index = (sorted_times.length * 0.95).ceil - 1 + p99_index = (sorted_times.length * 0.99).ceil - 1 + p95_time = sorted_times[p95_index] + p99_time = sorted_times[p99_index] + + puts "=== RESULTS SUMMARY ===" + puts "Total requests: #{REQUEST_COUNT}" + puts "Successful requests: #{success_count}" + puts "Failed requests: #{error_count}" + puts "Success rate: #{((success_count.to_f / REQUEST_COUNT) * 100).round(2)}%" + puts "" + puts "=== RESPONSE TIME STATISTICS (ms) ===" + puts "Average: #{average_time} ms" + puts "Minimum: #{min_time} ms" + puts "Maximum: #{max_time} ms" + puts "Median: #{median_time} ms" + puts "95th percentile: #{p95_time} ms" + puts "99th percentile: #{p99_time} ms" +else + puts "No response times recorded!" +end diff --git a/spec/acceptance/config/endpoints/hello.yml b/spec/acceptance/config/endpoints/hello.yml new file mode 100644 index 00000000..13c4a325 --- /dev/null +++ b/spec/acceptance/config/endpoints/hello.yml @@ -0,0 +1,2 @@ +path: /hello +handler: Hello diff --git a/spec/acceptance/plugins/handlers/hello.rb b/spec/acceptance/plugins/handlers/hello.rb new file mode 100644 index 00000000..9ea840ce --- /dev/null +++ b/spec/acceptance/plugins/handlers/hello.rb @@ -0,0 +1,11 @@ +# frozen_string_literal: true + +class Hello < Hooks::Plugins::Handlers::Base + def call(payload:, headers:, config:) + { + status: "success", + handler: self.class.name, + timestamp: Time.now.iso8601 + } + end +end