tenter 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: f38e303b6f15e746b96586d2a2a6e0e3ca0a2c4746cef91fec0bb455c03fd934
4
+ data.tar.gz: 38319bec27ca53fefc5fdb9f011e0607e3d47741df22f8586482615b9971d3aa
5
+ SHA512:
6
+ metadata.gz: 768b2d4c62fea0a0c2574bfb873ff8c07e7ab1a4fc535a8c32244bf8d8827e728db234aaf13fbe1febe35c6fe9e00a36a44430a19e6ec2485ad898a6927cbd31
7
+ data.tar.gz: b0281208e5189a643e7bd512f8f3a930e983c5f9f3fd106a41750fea263d54bd3c2eded9d4738802c86f9be647b9dc55364ea29cabf6749d5c109e073a7560bf
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,24 @@
1
+ This is free and unencumbered software released into the public domain.
2
+
3
+ Anyone is free to copy, modify, publish, use, compile, sell, or
4
+ distribute this software, either in source code form or as a compiled
5
+ binary, for any purpose, commercial or non-commercial, and by any
6
+ means.
7
+
8
+ In jurisdictions that recognize copyright laws, the author or authors
9
+ of this software dedicate any and all copyright interest in the
10
+ software to the public domain. We make this dedication for the benefit
11
+ of the public at large and to the detriment of our heirs and
12
+ successors. We intend this dedication to be an overt act of
13
+ relinquishment in perpetuity of all present and future rights to this
14
+ software under copyright law.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19
+ IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20
+ OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21
+ ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22
+ OTHER DEALINGS IN THE SOFTWARE.
23
+
24
+ For more information, please refer to <http://unlicense.org>
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "tenter/helpers"
4
+ require "tenter/hooks"
5
+ require "tenter/utils"
6
+ require "tenter/version"
7
+
8
+ module Tenter
9
+ def self.defaults
10
+ { doc_root: "/var/www/",
11
+ config_filename: "hooks.yaml",
12
+ command_dir: "commands",
13
+ log_file: "log/commands.log" }
14
+ end
15
+
16
+ def self.reset
17
+ @settings = self.defaults
18
+ end
19
+
20
+ def self.settings=(opts = {})
21
+ @settings = self.settings.merge opts
22
+ end
23
+
24
+ def self.settings
25
+ @settings ||= self.defaults
26
+ end
27
+ end
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "openssl"
4
+
5
+ module Tenter
6
+ module Helpers
7
+ def authenticate
8
+ msg = "X-Hub-Signature header not set"
9
+ halt 400, msg unless request.env['HTTP_X_HUB_SIGNATURE']
10
+
11
+ msg = "X-Hub-Signature header did not match"
12
+ halt 403, msg unless Tenter::Utils.dir_exists? params[:site_dir]
13
+
14
+ secret = Tenter::Utils.secret params[:site_dir]
15
+
16
+ request_sig = request.env['HTTP_X_HUB_SIGNATURE']
17
+ request_body = request.body.read
18
+ computed_sig = 'sha1=' +
19
+ OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha1'),
20
+ secret,
21
+ request_body)
22
+
23
+ msg = "X-Hub-Signature header did not match"
24
+ halt 403, msg unless Rack::Utils.secure_compare computed_sig, request_sig
25
+ end
26
+
27
+ def initiate
28
+ command = Tenter::Utils.command params[:command_name], params[:site_dir]
29
+
30
+ msg = "Command not found"
31
+ halt 400, msg unless File.file? command["path"]
32
+
33
+ msg = "[#{Time.now}] Initiating: #{command["path"]}\n"
34
+ Tenter::Utils.append_to_log command["log"], msg
35
+
36
+ pid = command["proc"].call
37
+ (ENV["APP_ENV"] != "test") ? Process.detach(pid) : Process.wait(pid)
38
+ end
39
+
40
+ def notify(message)
41
+ case message
42
+ when :initiated
43
+ return 200, "Command initiated"
44
+ when :missing
45
+ halt 404, "Page not found"
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "sinatra/base"
4
+
5
+ module Tenter
6
+ class Hooks < Sinatra::Base
7
+ helpers Tenter::Helpers
8
+
9
+ post %r{/run/(?<command_name>\w[^\\\/\s]*)/in/(?<site_dir>\w[^\\\/\s]*)/?} do
10
+ authenticate
11
+ initiate
12
+ notify :initiated
13
+ end
14
+
15
+ not_found do
16
+ notify :missing
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "yaml"
4
+
5
+ module Tenter
6
+ module Utils
7
+ def self.config(site_dir)
8
+ @config ||= {}
9
+ @config[site_dir] ||=
10
+ YAML.load_file(File.join(Tenter.settings[:doc_root],
11
+ site_dir,
12
+ Tenter.settings[:config_filename]))
13
+ end
14
+
15
+ def self.dir_exists?(site_dir)
16
+ File.directory? File.join(Tenter.settings[:doc_root], site_dir)
17
+ end
18
+
19
+ def self.secret(site_dir)
20
+ self.config(site_dir).fetch("secret", nil)
21
+ end
22
+
23
+ def self.command(command_name, site_dir)
24
+ ts = %q{ | xargs -L 1 sh -c 'printf "[%s] %s\n" "$(date +%Y-%m-%d\ %H:%M:%S\ %z )" "$*" ' sh}
25
+ command = {}
26
+ command["pwd"] = File.join(Tenter.settings[:doc_root], site_dir)
27
+ command["path"] = File.join(command["pwd"],
28
+ Tenter.settings[:command_dir],
29
+ command_name)
30
+ command["log"] = unless Tenter.settings[:log_file].nil?
31
+ File.join(command["pwd"], Tenter.settings[:log_file])
32
+ else
33
+ "/dev/null"
34
+ end
35
+ command["proc"] = Proc.new {
36
+ spawn command["path"] + ts, { :chdir => command["pwd"],
37
+ :out => [ command["log"], "a" ] }
38
+ }
39
+
40
+ return command
41
+ end
42
+
43
+ def self.append_to_log(log, statement)
44
+ File.write(log, statement, mode: "a")
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Tenter
4
+ VERSION = "0.1.0"
5
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "./lib/tenter/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "tenter"
7
+ s.version = Tenter::VERSION
8
+ s.authors = ["Michael Camilleri"]
9
+ s.email = ["mike@inqk.net"]
10
+ s.summary = "A web app for running user-defined commands"
11
+ s.description = <<-desc.strip.gsub(/\s+/, " ")
12
+ Tenter is a Sinatra-based application that provides webhooks for use by
13
+ GitHub.
14
+ desc
15
+ s.homepage = "https://github.com/pyrmont/tenter/"
16
+ s.licenses = "Unlicense"
17
+ s.required_ruby_version = ">= 2.5"
18
+
19
+ s.files = Dir["Gemfile", "LICENSE", "tenter.gemspec", "lib/tenter.rb",
20
+ "lib/**/*.rb"]
21
+ s.require_paths = ["lib"]
22
+
23
+ s.metadata["allowed_push_host"] = "https://rubygems.org"
24
+
25
+ s.add_runtime_dependency "sinatra", "~> 2.0"
26
+
27
+ s.add_development_dependency "minitest", "~> 5.11"
28
+ s.add_development_dependency "rack-test", "~> 1.1"
29
+ s.add_development_dependency "rake", "~> 12.3"
30
+ end
metadata ADDED
@@ -0,0 +1,109 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: tenter
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Michael Camilleri
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2019-07-07 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: sinatra
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '2.0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '2.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: minitest
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '5.11'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '5.11'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rack-test
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '1.1'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '1.1'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rake
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '12.3'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '12.3'
69
+ description: Tenter is a Sinatra-based application that provides webhooks for use
70
+ by GitHub.
71
+ email:
72
+ - mike@inqk.net
73
+ executables: []
74
+ extensions: []
75
+ extra_rdoc_files: []
76
+ files:
77
+ - Gemfile
78
+ - LICENSE
79
+ - lib/tenter.rb
80
+ - lib/tenter/helpers.rb
81
+ - lib/tenter/hooks.rb
82
+ - lib/tenter/utils.rb
83
+ - lib/tenter/version.rb
84
+ - tenter.gemspec
85
+ homepage: https://github.com/pyrmont/tenter/
86
+ licenses:
87
+ - Unlicense
88
+ metadata:
89
+ allowed_push_host: https://rubygems.org
90
+ post_install_message:
91
+ rdoc_options: []
92
+ require_paths:
93
+ - lib
94
+ required_ruby_version: !ruby/object:Gem::Requirement
95
+ requirements:
96
+ - - ">="
97
+ - !ruby/object:Gem::Version
98
+ version: '2.5'
99
+ required_rubygems_version: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ requirements: []
105
+ rubygems_version: 3.0.3
106
+ signing_key:
107
+ specification_version: 4
108
+ summary: A web app for running user-defined commands
109
+ test_files: []