@hybridlabor-api/aos 4.8.0 → 4.10.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.
- package/.agents/{agents.md → AGENTS.md} +3 -1
- package/.agents/nodes.json +3 -1
- package/.agents/vendor-manifest.json +23 -1
- package/.claude/agents/godmode-media-eventtech.md +1 -1
- package/.claude/hooks/conventional-commits.mjs +125 -0
- package/.claude/hooks/env-file-protection.mjs +105 -0
- package/.claude/hooks/go-gate.mjs +101 -81
- package/.claude/hooks/memb-inject.mjs +29 -1
- package/.claude/settings.json +13 -0
- package/.claude/workflows/startcycle-dispatch.mjs +23 -1
- package/.opencode/agents/godmode-media-eventtech.md +1 -1
- package/.opencode/plugins/bdb-aos.js +31 -4
- package/CLAUDE.md +0 -571
- package/README.de.md +1 -1
- package/README.md +1 -1
- package/README.pt.md +1 -1
- package/THIRD_PARTY_NOTICES.md +126 -0
- package/bin/aos-doctor.mjs +1 -1
- package/docs/skills_table.md +1 -1
- package/installer.js +187 -55
- package/package.json +7 -3
- package/packages/aos-cli/README.md +80 -0
- package/packages/aos-cli/bin/aos-cli.mjs +134 -0
- package/packages/aos-cli/core-skills.json +12 -0
- package/packages/aos-cli/extensions/aos.ts +321 -0
- package/packages/aos-cli/package-lock.json +1923 -0
- package/packages/aos-cli/package.json +29 -0
- package/packages/aos-cli/scripts/check-theme.mjs +63 -0
- package/packages/aos-cli/themes/aos.json +97 -0
- package/scripts/build-plugin-manifest.mjs +131 -0
- package/scripts/validate-skills.mjs +81 -6
- package/skills/basic/ao-orchestrator/SKILL.md +116 -0
- package/skills/basic/bdb-eventagency-skill/SKILL.md +252 -0
- package/skills/basic/bdb-shipping-skill/SKILL.md +161 -0
- package/skills/basic/godmode-eventtech/SKILL.md +4 -1
- package/skills/global_config/agenttrail/SKILL.md +6 -1
- package/skills/global_config/aos-project-init/SKILL.md +2 -0
- package/skills/global_config/aos-project-init/assets/AGENTS.template.md +1 -1
- package/skills/global_config/aos-project-init/scripts/aos-project-doctor.mjs +1 -1
- package/skills/global_config/aos-setup/SKILL.md +1 -1
- package/skills/global_config/aos-setup/scripts/aos-doctor.mjs +1 -1
- package/skills/global_config/ask-tim/SKILL.md +7 -7
- package/skills/global_config/bash-script-generator/SKILL.md +201 -0
- package/skills/global_config/bash-script-generator/assets/templates/standard-template.sh +96 -0
- package/skills/global_config/bash-script-generator/docs/bash-scripting-guide.md +729 -0
- package/skills/global_config/bash-script-generator/docs/generation-best-practices.md +193 -0
- package/skills/global_config/bash-script-generator/docs/script-patterns.md +566 -0
- package/skills/global_config/bash-script-generator/docs/text-processing-guide.md +437 -0
- package/skills/global_config/bash-script-generator/examples/log-analyzer.sh +92 -0
- package/skills/global_config/bash-script-generator/scripts/generate_script_template.sh +123 -0
- package/skills/global_config/bash-script-generator/scripts/run_ci_checks.sh +172 -0
- package/skills/global_config/bash-script-generator/scripts/test_generator.sh +413 -0
- package/skills/global_config/bash-script-validator/SKILL.md +249 -0
- package/skills/global_config/bash-script-validator/docs/awk-reference.md +449 -0
- package/skills/global_config/bash-script-validator/docs/bash-reference.md +468 -0
- package/skills/global_config/bash-script-validator/docs/common-mistakes.md +623 -0
- package/skills/global_config/bash-script-validator/docs/grep-reference.md +395 -0
- package/skills/global_config/bash-script-validator/docs/regex-reference.md +391 -0
- package/skills/global_config/bash-script-validator/docs/sed-reference.md +454 -0
- package/skills/global_config/bash-script-validator/docs/shell-reference.md +463 -0
- package/skills/global_config/bash-script-validator/docs/shellcheck-reference.md +399 -0
- package/skills/global_config/bash-script-validator/examples/bad-bash.sh +55 -0
- package/skills/global_config/bash-script-validator/examples/bad-shell.sh +54 -0
- package/skills/global_config/bash-script-validator/examples/good-bash.sh +71 -0
- package/skills/global_config/bash-script-validator/examples/good-shell.sh +69 -0
- package/skills/global_config/bash-script-validator/scripts/run_ci_checks.sh +23 -0
- package/skills/global_config/bash-script-validator/scripts/shellcheck_wrapper.sh +174 -0
- package/skills/global_config/bash-script-validator/scripts/test_validate.sh +446 -0
- package/skills/global_config/bash-script-validator/scripts/validate.sh +512 -0
- package/skills/global_config/ci-pipeline/SKILL.md +135 -0
- package/skills/global_config/deja-memory/SKILL.md +3 -1
- package/skills/global_config/dispatching-parallel-agents/SKILL.md +170 -0
- package/skills/global_config/dockerfile-generator/SKILL.md +1038 -0
- package/skills/global_config/dockerfile-generator/examples/example.dockerignore +95 -0
- package/skills/global_config/dockerfile-generator/examples/golang-distroless.Dockerfile +34 -0
- package/skills/global_config/dockerfile-generator/examples/java-springboot.Dockerfile +45 -0
- package/skills/global_config/dockerfile-generator/examples/nextjs-production.Dockerfile +49 -0
- package/skills/global_config/dockerfile-generator/examples/nodejs-multistage.Dockerfile +55 -0
- package/skills/global_config/dockerfile-generator/examples/python-fastapi.Dockerfile +48 -0
- package/skills/global_config/dockerfile-generator/references/language_specific_guides.md +510 -0
- package/skills/global_config/dockerfile-generator/references/multistage_builds.md +570 -0
- package/skills/global_config/dockerfile-generator/references/optimization_patterns.md +492 -0
- package/skills/global_config/dockerfile-generator/references/security_best_practices.md +375 -0
- package/skills/global_config/dockerfile-generator/scripts/generate_dockerignore.sh +199 -0
- package/skills/global_config/dockerfile-generator/scripts/generate_golang.sh +172 -0
- package/skills/global_config/dockerfile-generator/scripts/generate_java.sh +185 -0
- package/skills/global_config/dockerfile-generator/scripts/generate_nodejs.sh +279 -0
- package/skills/global_config/dockerfile-generator/scripts/generate_python.sh +218 -0
- package/skills/global_config/dockerfile-generator/scripts/test_generator.sh +210 -0
- package/skills/global_config/dockerfile-validator/SKILL.md +300 -0
- package/skills/global_config/dockerfile-validator/examples/.dockerignore.example +34 -0
- package/skills/global_config/dockerfile-validator/examples/bad-example.Dockerfile +37 -0
- package/skills/global_config/dockerfile-validator/examples/golang-distroless.Dockerfile +50 -0
- package/skills/global_config/dockerfile-validator/examples/good-example.Dockerfile +52 -0
- package/skills/global_config/dockerfile-validator/examples/python-optimized.Dockerfile +53 -0
- package/skills/global_config/dockerfile-validator/examples/security-issues.Dockerfile +42 -0
- package/skills/global_config/dockerfile-validator/references/docker_best_practices.md +348 -0
- package/skills/global_config/dockerfile-validator/references/optimization_guide.md +473 -0
- package/skills/global_config/dockerfile-validator/references/security_checklist.md +208 -0
- package/skills/global_config/dockerfile-validator/scripts/dockerfile-validate.sh +699 -0
- package/skills/global_config/dockerfile-validator/scripts/test_validate.sh +35 -0
- package/skills/global_config/dockerfile-validator/tests/fixtures/copy-before-yarn-lock-read.Dockerfile +6 -0
- package/skills/global_config/dockerfile-validator/tests/fixtures/copy-before-yarn.Dockerfile +6 -0
- package/skills/global_config/dockerfile-validator/tests/fixtures/from-platform-nonroot.Dockerfile +7 -0
- package/skills/global_config/dockerfile-validator/tests/test_regression.sh +164 -0
- package/skills/global_config/finishing-a-development-branch/SKILL.md +228 -0
- package/skills/global_config/github-actions-generator/SKILL.md +353 -0
- package/skills/global_config/github-actions-generator/assets/templates/action/composite/action.yml +82 -0
- package/skills/global_config/github-actions-generator/assets/templates/action/docker/Dockerfile +25 -0
- package/skills/global_config/github-actions-generator/assets/templates/action/docker/action.yml +42 -0
- package/skills/global_config/github-actions-generator/assets/templates/action/docker/entrypoint.sh +27 -0
- package/skills/global_config/github-actions-generator/assets/templates/action/javascript/action.yml +33 -0
- package/skills/global_config/github-actions-generator/assets/templates/action/javascript/index.js +50 -0
- package/skills/global_config/github-actions-generator/assets/templates/action/javascript/package.json +27 -0
- package/skills/global_config/github-actions-generator/assets/templates/workflow/basic_workflow.yml +242 -0
- package/skills/global_config/github-actions-generator/assets/templates/workflow/reusable_workflow.yml +106 -0
- package/skills/global_config/github-actions-generator/examples/README.md +147 -0
- package/skills/global_config/github-actions-generator/examples/actions/setup-node-cached/action.yml +93 -0
- package/skills/global_config/github-actions-generator/examples/caching/docker-buildkit.yml +256 -0
- package/skills/global_config/github-actions-generator/examples/security/dependency-review.yml +62 -0
- package/skills/global_config/github-actions-generator/examples/security/sbom-attestation.yml +119 -0
- package/skills/global_config/github-actions-generator/examples/triggers/chatops-commands.yml +475 -0
- package/skills/global_config/github-actions-generator/examples/triggers/repository-dispatch.yml +418 -0
- package/skills/global_config/github-actions-generator/examples/triggers/workflow-orchestration.yml +404 -0
- package/skills/global_config/github-actions-generator/examples/workflows/docker-build-push.yml +68 -0
- package/skills/global_config/github-actions-generator/examples/workflows/go-ci.yml +161 -0
- package/skills/global_config/github-actions-generator/examples/workflows/monorepo-ci.yml +340 -0
- package/skills/global_config/github-actions-generator/examples/workflows/multi-environment-deploy.yml +406 -0
- package/skills/global_config/github-actions-generator/examples/workflows/nodejs-ci.yml +122 -0
- package/skills/global_config/github-actions-generator/examples/workflows/python-ci.yml +157 -0
- package/skills/global_config/github-actions-generator/examples/workflows/scheduled-tasks.yml +376 -0
- package/skills/global_config/github-actions-generator/references/advanced-triggers.md +917 -0
- package/skills/global_config/github-actions-generator/references/best-practices.md +755 -0
- package/skills/global_config/github-actions-generator/references/common-actions.md +715 -0
- package/skills/global_config/github-actions-generator/references/custom-actions.md +320 -0
- package/skills/global_config/github-actions-generator/references/expressions-and-contexts.md +688 -0
- package/skills/global_config/github-actions-generator/references/modern-features.md +421 -0
- package/skills/global_config/github-actions-generator/scripts/test_generator.sh +344 -0
- package/skills/global_config/github-actions-templates/SKILL.md +7 -0
- package/skills/global_config/github-actions-validator/SKILL.md +576 -0
- package/skills/global_config/github-actions-validator/examples/README.md +88 -0
- package/skills/global_config/github-actions-validator/examples/outdated-versions.yml +76 -0
- package/skills/global_config/github-actions-validator/examples/valid-ci.yml +79 -0
- package/skills/global_config/github-actions-validator/examples/with-errors.yml +47 -0
- package/skills/global_config/github-actions-validator/references/act_usage.md +233 -0
- package/skills/global_config/github-actions-validator/references/action_versions.md +122 -0
- package/skills/global_config/github-actions-validator/references/actionlint_usage.md +343 -0
- package/skills/global_config/github-actions-validator/references/common_errors.md +512 -0
- package/skills/global_config/github-actions-validator/references/modern_features.md +384 -0
- package/skills/global_config/github-actions-validator/references/runners.md +317 -0
- package/skills/global_config/github-actions-validator/scripts/install_tools.sh +113 -0
- package/skills/global_config/github-actions-validator/scripts/validate_workflow.sh +910 -0
- package/skills/global_config/github-actions-validator/tests/test_validate_workflow.sh +237 -0
- package/skills/global_config/makefile-generator/SKILL.md +614 -0
- package/skills/global_config/makefile-generator/assets/templates/.gitkeep +1 -0
- package/skills/global_config/makefile-generator/docs/makefile-structure.md +530 -0
- package/skills/global_config/makefile-generator/docs/optimization-guide.md +784 -0
- package/skills/global_config/makefile-generator/docs/patterns-guide.md +642 -0
- package/skills/global_config/makefile-generator/docs/security-guide.md +361 -0
- package/skills/global_config/makefile-generator/docs/targets-guide.md +642 -0
- package/skills/global_config/makefile-generator/docs/variables-guide.md +596 -0
- package/skills/global_config/makefile-generator/scripts/add_standard_targets.sh +539 -0
- package/skills/global_config/makefile-generator/scripts/generate_makefile_template.sh +690 -0
- package/skills/global_config/makefile-generator/test/test_helper_scripts.sh +190 -0
- package/skills/global_config/makefile-validator/SKILL.md +244 -0
- package/skills/global_config/makefile-validator/docs/bake-tool.md +1000 -0
- package/skills/global_config/makefile-validator/docs/best-practices.md +858 -0
- package/skills/global_config/makefile-validator/docs/common-mistakes.md +944 -0
- package/skills/global_config/makefile-validator/examples/bad-makefile.mk +77 -0
- package/skills/global_config/makefile-validator/examples/good-makefile.mk +103 -0
- package/skills/global_config/makefile-validator/scripts/test_validate.sh +382 -0
- package/skills/global_config/makefile-validator/scripts/validate_makefile.sh +712 -0
- package/skills/global_config/{MCP_Manage → mcp-manage}/SKILL.md +3 -3
- package/skills/global_config/plan-canvas/SKILL.md +9 -2
- package/skills/global_config/plan-canvas/scripts/lib/plan-canvas/ui.js +10 -2
- package/skills/global_config/plan-canvas/scripts/plan-canvas.js +1 -1
- package/skills/global_config/read-the-damn-docs/SKILL.md +175 -0
- package/skills/global_config/requesting-code-review/SKILL.md +98 -0
- package/skills/global_config/requesting-code-review/code-reviewer.md +198 -0
- package/skills/global_config/using-git-worktrees/SKILL.md +170 -0
- package/skills/global_config/verification-before-completion/SKILL.md +123 -0
- package/skills/global_config/writing-plans/SKILL.md +126 -46
- package/skills/global_config/writing-plans-legacy/SKILL.md +152 -0
- package/.claude/CLAUDE.md +0 -12
- package/mcps/RhinoMCP/docs/content/docs/getting-started/gemini.md +0 -61
- /package/{GEMINI.md → RULES.md} +0 -0
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
#
|
|
3
|
+
# Deterministic CI validation entrypoint for bash-script-generator.
|
|
4
|
+
# Runs:
|
|
5
|
+
# 1) bash -n syntax checks
|
|
6
|
+
# 2) shellcheck -x checks (optional or required)
|
|
7
|
+
# 3) regression tests (scripts/test_generator.sh)
|
|
8
|
+
#
|
|
9
|
+
|
|
10
|
+
set -euo pipefail
|
|
11
|
+
|
|
12
|
+
readonly SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
13
|
+
readonly SKILL_DIR="$(cd "${SCRIPT_DIR}/.." && pwd)"
|
|
14
|
+
readonly TEST_RUNNER="${SCRIPT_DIR}/test_generator.sh"
|
|
15
|
+
|
|
16
|
+
usage() {
|
|
17
|
+
cat <<EOF
|
|
18
|
+
Usage: ${0##*/} [OPTIONS]
|
|
19
|
+
|
|
20
|
+
Run deterministic checks for bash-script-generator.
|
|
21
|
+
|
|
22
|
+
Options:
|
|
23
|
+
--require-shellcheck Fail if shellcheck is unavailable.
|
|
24
|
+
--skip-shellcheck Skip shellcheck stage.
|
|
25
|
+
--skip-regression-tests Skip scripts/test_generator.sh.
|
|
26
|
+
-h, --help Show this help message.
|
|
27
|
+
|
|
28
|
+
Environment:
|
|
29
|
+
SHELLCHECK_BIN Override shellcheck binary/path (default: shellcheck)
|
|
30
|
+
CI=true|1 Defaults to --require-shellcheck unless explicitly overridden
|
|
31
|
+
EOF
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
is_true() {
|
|
35
|
+
local value="$1"
|
|
36
|
+
[[ "$value" == "true" || "$value" == "1" ]]
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
command_is_available() {
|
|
40
|
+
local command_name="$1"
|
|
41
|
+
if [[ "$command_name" == */* ]]; then
|
|
42
|
+
[[ -x "$command_name" ]]
|
|
43
|
+
else
|
|
44
|
+
command -v "$command_name" >/dev/null 2>&1
|
|
45
|
+
fi
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
collect_shell_files() {
|
|
49
|
+
SHELL_FILES=()
|
|
50
|
+
while IFS= read -r file; do
|
|
51
|
+
SHELL_FILES+=("$file")
|
|
52
|
+
done < <(
|
|
53
|
+
{
|
|
54
|
+
find "${SCRIPT_DIR}" -maxdepth 1 -type f -name "*.sh"
|
|
55
|
+
find "${SKILL_DIR}/examples" -maxdepth 1 -type f -name "*.sh"
|
|
56
|
+
find "${SKILL_DIR}/assets/templates" -maxdepth 1 -type f -name "*.sh"
|
|
57
|
+
} | LC_ALL=C sort
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
if [[ "${#SHELL_FILES[@]}" -eq 0 ]]; then
|
|
61
|
+
echo "Error: No shell files found to validate." >&2
|
|
62
|
+
return 1
|
|
63
|
+
fi
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
run_syntax_checks() {
|
|
67
|
+
echo "[1/3] bash -n syntax checks"
|
|
68
|
+
local shell_file
|
|
69
|
+
for shell_file in "${SHELL_FILES[@]}"; do
|
|
70
|
+
bash -n "${shell_file}"
|
|
71
|
+
done
|
|
72
|
+
echo " PASS: bash -n succeeded for ${#SHELL_FILES[@]} file(s)"
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
run_shellcheck_checks() {
|
|
76
|
+
local shellcheck_bin="$1"
|
|
77
|
+
local require_shellcheck="$2"
|
|
78
|
+
local skip_shellcheck="$3"
|
|
79
|
+
|
|
80
|
+
if [[ "$skip_shellcheck" -eq 1 ]]; then
|
|
81
|
+
echo "[2/3] shellcheck -x checks"
|
|
82
|
+
echo " SKIP: shellcheck stage disabled via --skip-shellcheck"
|
|
83
|
+
return 0
|
|
84
|
+
fi
|
|
85
|
+
|
|
86
|
+
echo "[2/3] shellcheck -x checks"
|
|
87
|
+
if ! command_is_available "$shellcheck_bin"; then
|
|
88
|
+
if [[ "$require_shellcheck" -eq 1 ]]; then
|
|
89
|
+
echo "Error: shellcheck is required but not available (${shellcheck_bin})." >&2
|
|
90
|
+
return 1
|
|
91
|
+
fi
|
|
92
|
+
echo " SKIP: shellcheck unavailable (${shellcheck_bin}); continuing without shellcheck"
|
|
93
|
+
return 0
|
|
94
|
+
fi
|
|
95
|
+
|
|
96
|
+
local shell_file
|
|
97
|
+
for shell_file in "${SHELL_FILES[@]}"; do
|
|
98
|
+
"$shellcheck_bin" -x "${shell_file}"
|
|
99
|
+
done
|
|
100
|
+
echo " PASS: shellcheck succeeded for ${#SHELL_FILES[@]} file(s)"
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
run_regression_tests() {
|
|
104
|
+
local skip_regression_tests="$1"
|
|
105
|
+
|
|
106
|
+
echo "[3/3] regression tests"
|
|
107
|
+
if [[ "$skip_regression_tests" -eq 1 ]]; then
|
|
108
|
+
echo " SKIP: regression suite disabled via --skip-regression-tests"
|
|
109
|
+
return 0
|
|
110
|
+
fi
|
|
111
|
+
|
|
112
|
+
bash "${TEST_RUNNER}"
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
main() {
|
|
116
|
+
local require_shellcheck=0
|
|
117
|
+
local skip_shellcheck=0
|
|
118
|
+
local skip_regression_tests=0
|
|
119
|
+
local shellcheck_mode_overridden=0
|
|
120
|
+
local shellcheck_bin="${SHELLCHECK_BIN:-shellcheck}"
|
|
121
|
+
|
|
122
|
+
while [[ $# -gt 0 ]]; do
|
|
123
|
+
case "$1" in
|
|
124
|
+
--require-shellcheck)
|
|
125
|
+
require_shellcheck=1
|
|
126
|
+
skip_shellcheck=0
|
|
127
|
+
shellcheck_mode_overridden=1
|
|
128
|
+
;;
|
|
129
|
+
--skip-shellcheck)
|
|
130
|
+
skip_shellcheck=1
|
|
131
|
+
require_shellcheck=0
|
|
132
|
+
shellcheck_mode_overridden=1
|
|
133
|
+
;;
|
|
134
|
+
--skip-regression-tests)
|
|
135
|
+
skip_regression_tests=1
|
|
136
|
+
;;
|
|
137
|
+
-h|--help)
|
|
138
|
+
usage
|
|
139
|
+
exit 0
|
|
140
|
+
;;
|
|
141
|
+
*)
|
|
142
|
+
echo "Error: Unknown option: $1" >&2
|
|
143
|
+
usage
|
|
144
|
+
exit 1
|
|
145
|
+
;;
|
|
146
|
+
esac
|
|
147
|
+
shift
|
|
148
|
+
done
|
|
149
|
+
|
|
150
|
+
if [[ "$shellcheck_mode_overridden" -eq 0 ]] && is_true "${CI:-}"; then
|
|
151
|
+
require_shellcheck=1
|
|
152
|
+
fi
|
|
153
|
+
|
|
154
|
+
if [[ "$skip_shellcheck" -eq 1 && "$require_shellcheck" -eq 1 ]]; then
|
|
155
|
+
echo "Error: --skip-shellcheck and --require-shellcheck cannot be used together." >&2
|
|
156
|
+
exit 1
|
|
157
|
+
fi
|
|
158
|
+
|
|
159
|
+
export LC_ALL=C
|
|
160
|
+
export LANG=C
|
|
161
|
+
export TZ=UTC
|
|
162
|
+
|
|
163
|
+
collect_shell_files
|
|
164
|
+
run_syntax_checks
|
|
165
|
+
run_shellcheck_checks "$shellcheck_bin" "$require_shellcheck" "$skip_shellcheck"
|
|
166
|
+
run_regression_tests "$skip_regression_tests"
|
|
167
|
+
|
|
168
|
+
echo ""
|
|
169
|
+
echo "All configured CI checks passed."
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
main "$@"
|
|
@@ -0,0 +1,413 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
#
|
|
3
|
+
# Regression test suite for bash-script-generator
|
|
4
|
+
#
|
|
5
|
+
# Tests:
|
|
6
|
+
# 1. generate_script_template.sh — argument handling and file generation
|
|
7
|
+
# 2. log-analyzer.sh — functional behaviour
|
|
8
|
+
# 3. run_ci_checks.sh — deterministic validation wiring
|
|
9
|
+
#
|
|
10
|
+
# Exit 0 when all assertions pass; non-zero on any failure.
|
|
11
|
+
#
|
|
12
|
+
|
|
13
|
+
set -euo pipefail
|
|
14
|
+
|
|
15
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
16
|
+
readonly SCRIPT_DIR
|
|
17
|
+
GENERATOR="$SCRIPT_DIR/generate_script_template.sh"
|
|
18
|
+
CI_RUNNER="$SCRIPT_DIR/run_ci_checks.sh"
|
|
19
|
+
LOG_ANALYZER="$SCRIPT_DIR/../examples/log-analyzer.sh"
|
|
20
|
+
|
|
21
|
+
PASS=0
|
|
22
|
+
FAIL=0
|
|
23
|
+
|
|
24
|
+
# ─── helpers ────────────────────────────────────────────────────────────────
|
|
25
|
+
|
|
26
|
+
pass() { echo " PASS: $1"; PASS=$((PASS + 1)); }
|
|
27
|
+
fail() { echo " FAIL: $1"; FAIL=$((FAIL + 1)); }
|
|
28
|
+
|
|
29
|
+
# Run a command silently and return its exit code without aborting this script.
|
|
30
|
+
run_exit_code() {
|
|
31
|
+
local exit_code=0
|
|
32
|
+
"$@" >/dev/null 2>&1 || exit_code=$?
|
|
33
|
+
echo "$exit_code"
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
assert_exit_code() {
|
|
37
|
+
local label="$1"
|
|
38
|
+
local expected="$2"
|
|
39
|
+
shift 2
|
|
40
|
+
|
|
41
|
+
local actual
|
|
42
|
+
actual=$(run_exit_code "$@")
|
|
43
|
+
|
|
44
|
+
if [[ "$actual" -eq "$expected" ]]; then
|
|
45
|
+
pass "$label (exit $actual)"
|
|
46
|
+
else
|
|
47
|
+
fail "$label — expected exit $expected, got $actual"
|
|
48
|
+
echo " --- command output ---"
|
|
49
|
+
"$@" 2>&1 | sed 's/^/ /' || true
|
|
50
|
+
echo " --- end output ---"
|
|
51
|
+
fi
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
# Assert that a pattern IS present in the combined stdout+stderr of a command.
|
|
55
|
+
assert_output_contains() {
|
|
56
|
+
local label="$1"
|
|
57
|
+
local pattern="$2"
|
|
58
|
+
shift 2
|
|
59
|
+
|
|
60
|
+
local output
|
|
61
|
+
output=$("$@" 2>&1 || true)
|
|
62
|
+
|
|
63
|
+
if echo "$output" | grep -qE "$pattern"; then
|
|
64
|
+
pass "$label"
|
|
65
|
+
else
|
|
66
|
+
fail "$label — pattern not found: $pattern"
|
|
67
|
+
echo " --- command output ---"
|
|
68
|
+
echo "$output" | sed 's/^/ /'
|
|
69
|
+
echo " --- end output ---"
|
|
70
|
+
fi
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
# Assert that a pattern is NOT present in the combined stdout+stderr of a command.
|
|
74
|
+
assert_output_not_contains() {
|
|
75
|
+
local label="$1"
|
|
76
|
+
local pattern="$2"
|
|
77
|
+
shift 2
|
|
78
|
+
|
|
79
|
+
local output
|
|
80
|
+
output=$("$@" 2>&1 || true)
|
|
81
|
+
|
|
82
|
+
if echo "$output" | grep -qE "$pattern"; then
|
|
83
|
+
fail "$label — unexpected pattern found: $pattern"
|
|
84
|
+
echo " --- command output ---"
|
|
85
|
+
echo "$output" | sed 's/^/ /'
|
|
86
|
+
echo " --- end output ---"
|
|
87
|
+
else
|
|
88
|
+
pass "$label"
|
|
89
|
+
fi
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
# ─── setup ──────────────────────────────────────────────────────────────────
|
|
93
|
+
|
|
94
|
+
TEMP_DIR=$(mktemp -d)
|
|
95
|
+
trap 'rm -rf "${TEMP_DIR}"' EXIT
|
|
96
|
+
|
|
97
|
+
# Fixture log file used by log-analyzer tests
|
|
98
|
+
LOG_FILE="${TEMP_DIR}/app.log"
|
|
99
|
+
cat > "$LOG_FILE" << 'EOF'
|
|
100
|
+
2024-01-15 10:00:01 INFO: App started
|
|
101
|
+
2024-01-15 10:00:02 DEBUG: Loading config
|
|
102
|
+
2024-01-15 10:00:03 ERROR: Connection refused to database
|
|
103
|
+
2024-01-15 10:00:04 ERROR: Connection refused to database
|
|
104
|
+
2024-01-15 10:00:05 WARN: Retry attempt
|
|
105
|
+
2024-01-15 10:00:06 ERROR: Timeout on upstream request
|
|
106
|
+
2024-01-15 10:00:07 INFO: Request complete
|
|
107
|
+
2024-01-15 10:00:08 FATAL: Critical failure
|
|
108
|
+
EOF
|
|
109
|
+
|
|
110
|
+
echo "Running bash-script-generator tests..."
|
|
111
|
+
|
|
112
|
+
# ─── generate_script_template.sh: argument handling ─────────────────────────
|
|
113
|
+
|
|
114
|
+
echo ""
|
|
115
|
+
echo "[generate_script_template.sh — argument handling]"
|
|
116
|
+
|
|
117
|
+
assert_exit_code \
|
|
118
|
+
"no args exits non-zero" \
|
|
119
|
+
1 \
|
|
120
|
+
bash "$GENERATOR"
|
|
121
|
+
|
|
122
|
+
assert_exit_code \
|
|
123
|
+
"--help exits 0" \
|
|
124
|
+
0 \
|
|
125
|
+
bash "$GENERATOR" --help
|
|
126
|
+
|
|
127
|
+
assert_exit_code \
|
|
128
|
+
"-h exits 0" \
|
|
129
|
+
0 \
|
|
130
|
+
bash "$GENERATOR" -h
|
|
131
|
+
|
|
132
|
+
assert_exit_code \
|
|
133
|
+
"unknown template exits non-zero" \
|
|
134
|
+
1 \
|
|
135
|
+
bash "$GENERATOR" nonexistent-template
|
|
136
|
+
|
|
137
|
+
assert_exit_code \
|
|
138
|
+
"too many args exits non-zero" \
|
|
139
|
+
1 \
|
|
140
|
+
bash "$GENERATOR" standard out.sh extra-arg
|
|
141
|
+
|
|
142
|
+
assert_exit_code \
|
|
143
|
+
"traversal template_type payload is rejected" \
|
|
144
|
+
1 \
|
|
145
|
+
bash "$GENERATOR" ../templates/standard
|
|
146
|
+
|
|
147
|
+
assert_output_contains \
|
|
148
|
+
"traversal payload shows invalid template_type error" \
|
|
149
|
+
"Invalid TEMPLATE_TYPE" \
|
|
150
|
+
bash "$GENERATOR" ../templates/standard
|
|
151
|
+
|
|
152
|
+
assert_exit_code \
|
|
153
|
+
"slash and dot traversal payload is rejected" \
|
|
154
|
+
1 \
|
|
155
|
+
bash "$GENERATOR" standard/../../evil
|
|
156
|
+
|
|
157
|
+
assert_output_contains \
|
|
158
|
+
"slash and dot traversal payload shows invalid template_type error" \
|
|
159
|
+
"Invalid TEMPLATE_TYPE" \
|
|
160
|
+
bash "$GENERATOR" standard/../../evil
|
|
161
|
+
|
|
162
|
+
assert_output_contains \
|
|
163
|
+
"no-args error mentions TEMPLATE_TYPE" \
|
|
164
|
+
"TEMPLATE_TYPE" \
|
|
165
|
+
bash "$GENERATOR"
|
|
166
|
+
|
|
167
|
+
assert_output_contains \
|
|
168
|
+
"unknown template error lists available templates" \
|
|
169
|
+
"Available templates" \
|
|
170
|
+
bash "$GENERATOR" nonexistent-template
|
|
171
|
+
|
|
172
|
+
# ─── generate_script_template.sh: file generation ───────────────────────────
|
|
173
|
+
|
|
174
|
+
echo ""
|
|
175
|
+
echo "[generate_script_template.sh — file generation]"
|
|
176
|
+
|
|
177
|
+
OUTPUT="${TEMP_DIR}/generated.sh"
|
|
178
|
+
assert_exit_code \
|
|
179
|
+
"standard template with explicit output exits 0" \
|
|
180
|
+
0 \
|
|
181
|
+
bash "$GENERATOR" standard "$OUTPUT"
|
|
182
|
+
|
|
183
|
+
if [[ -f "$OUTPUT" ]]; then
|
|
184
|
+
pass "output file was created"
|
|
185
|
+
else
|
|
186
|
+
fail "output file was not created"
|
|
187
|
+
fi
|
|
188
|
+
|
|
189
|
+
if [[ -x "$OUTPUT" ]]; then
|
|
190
|
+
pass "output file is executable (chmod u+x applied)"
|
|
191
|
+
else
|
|
192
|
+
fail "output file is not executable"
|
|
193
|
+
fi
|
|
194
|
+
|
|
195
|
+
assert_output_contains \
|
|
196
|
+
"generated file has bash shebang" \
|
|
197
|
+
"#!/usr/bin/env bash" \
|
|
198
|
+
cat "$OUTPUT"
|
|
199
|
+
|
|
200
|
+
assert_output_contains \
|
|
201
|
+
"generated file has strict mode" \
|
|
202
|
+
"set -euo pipefail" \
|
|
203
|
+
cat "$OUTPUT"
|
|
204
|
+
|
|
205
|
+
assert_output_contains \
|
|
206
|
+
"generated file has numeric LOG_LEVEL" \
|
|
207
|
+
"LOG_LEVEL=1" \
|
|
208
|
+
cat "$OUTPUT"
|
|
209
|
+
|
|
210
|
+
# Syntax check: the generated script must be parseable by bash
|
|
211
|
+
if bash -n "$OUTPUT" 2>/dev/null; then
|
|
212
|
+
pass "generated file passes bash -n syntax check"
|
|
213
|
+
else
|
|
214
|
+
fail "generated file has syntax errors"
|
|
215
|
+
fi
|
|
216
|
+
|
|
217
|
+
# Overwrite: generating into an existing path must succeed silently
|
|
218
|
+
assert_exit_code \
|
|
219
|
+
"overwriting existing output file exits 0" \
|
|
220
|
+
0 \
|
|
221
|
+
bash "$GENERATOR" standard "$OUTPUT"
|
|
222
|
+
|
|
223
|
+
# Nested directories must be created automatically
|
|
224
|
+
NESTED="${TEMP_DIR}/a/b/c/nested.sh"
|
|
225
|
+
assert_exit_code \
|
|
226
|
+
"output into non-existent nested directory exits 0" \
|
|
227
|
+
0 \
|
|
228
|
+
bash "$GENERATOR" standard "$NESTED"
|
|
229
|
+
|
|
230
|
+
if [[ -f "$NESTED" ]]; then
|
|
231
|
+
pass "nested output file was created"
|
|
232
|
+
else
|
|
233
|
+
fail "nested output file was not created"
|
|
234
|
+
fi
|
|
235
|
+
|
|
236
|
+
# Default output path: when no OUTPUT_FILE is given the file lands in CWD
|
|
237
|
+
ORIG_DIR="$(pwd)"
|
|
238
|
+
WORK_DIR="${TEMP_DIR}/workspace"
|
|
239
|
+
mkdir -p "$WORK_DIR"
|
|
240
|
+
cd "$WORK_DIR"
|
|
241
|
+
assert_exit_code \
|
|
242
|
+
"default output path (no output arg) exits 0" \
|
|
243
|
+
0 \
|
|
244
|
+
bash "$GENERATOR" standard
|
|
245
|
+
if [[ -f "${WORK_DIR}/standard-script.sh" ]]; then
|
|
246
|
+
pass "default output file ./standard-script.sh was created"
|
|
247
|
+
else
|
|
248
|
+
fail "default output file ./standard-script.sh was not created"
|
|
249
|
+
fi
|
|
250
|
+
|
|
251
|
+
TRAVERSAL_TARGET="${TEMP_DIR}/templates/standard-script.sh"
|
|
252
|
+
rm -rf "${TEMP_DIR}/templates"
|
|
253
|
+
assert_exit_code \
|
|
254
|
+
"traversal payload with default output exits non-zero" \
|
|
255
|
+
1 \
|
|
256
|
+
bash "$GENERATOR" ../templates/standard
|
|
257
|
+
if [[ ! -e "$TRAVERSAL_TARGET" ]]; then
|
|
258
|
+
pass "traversal payload did not create file outside current directory"
|
|
259
|
+
else
|
|
260
|
+
fail "traversal payload created unexpected file: $TRAVERSAL_TARGET"
|
|
261
|
+
fi
|
|
262
|
+
cd "$ORIG_DIR"
|
|
263
|
+
|
|
264
|
+
# ─── log-analyzer.sh: argument handling ─────────────────────────────────────
|
|
265
|
+
|
|
266
|
+
echo ""
|
|
267
|
+
echo "[log-analyzer.sh — argument handling]"
|
|
268
|
+
|
|
269
|
+
assert_exit_code \
|
|
270
|
+
"no file arg exits non-zero" \
|
|
271
|
+
1 \
|
|
272
|
+
bash "$LOG_ANALYZER"
|
|
273
|
+
|
|
274
|
+
assert_exit_code \
|
|
275
|
+
"-h exits 0" \
|
|
276
|
+
0 \
|
|
277
|
+
bash "$LOG_ANALYZER" -h
|
|
278
|
+
|
|
279
|
+
assert_exit_code \
|
|
280
|
+
"nonexistent file exits non-zero" \
|
|
281
|
+
1 \
|
|
282
|
+
bash "$LOG_ANALYZER" /nonexistent/file.log
|
|
283
|
+
|
|
284
|
+
assert_exit_code \
|
|
285
|
+
"invalid report type exits non-zero" \
|
|
286
|
+
1 \
|
|
287
|
+
bash "$LOG_ANALYZER" -t badtype "$LOG_FILE"
|
|
288
|
+
|
|
289
|
+
# ─── log-analyzer.sh: functional behaviour ──────────────────────────────────
|
|
290
|
+
|
|
291
|
+
echo ""
|
|
292
|
+
echo "[log-analyzer.sh — functional behaviour]"
|
|
293
|
+
|
|
294
|
+
assert_exit_code \
|
|
295
|
+
"summary report exits 0" \
|
|
296
|
+
0 \
|
|
297
|
+
bash "$LOG_ANALYZER" "$LOG_FILE"
|
|
298
|
+
|
|
299
|
+
assert_output_contains \
|
|
300
|
+
"summary report shows total lines" \
|
|
301
|
+
"Total lines" \
|
|
302
|
+
bash "$LOG_ANALYZER" "$LOG_FILE"
|
|
303
|
+
|
|
304
|
+
assert_output_contains \
|
|
305
|
+
"summary shows ERROR count" \
|
|
306
|
+
"ERROR" \
|
|
307
|
+
bash "$LOG_ANALYZER" "$LOG_FILE"
|
|
308
|
+
|
|
309
|
+
assert_output_contains \
|
|
310
|
+
"summary shows FATAL count" \
|
|
311
|
+
"FATAL" \
|
|
312
|
+
bash "$LOG_ANALYZER" "$LOG_FILE"
|
|
313
|
+
|
|
314
|
+
assert_exit_code \
|
|
315
|
+
"errors report exits 0" \
|
|
316
|
+
0 \
|
|
317
|
+
bash "$LOG_ANALYZER" -t errors "$LOG_FILE"
|
|
318
|
+
|
|
319
|
+
assert_output_contains \
|
|
320
|
+
"errors report shows total errors" \
|
|
321
|
+
"Total errors" \
|
|
322
|
+
bash "$LOG_ANALYZER" -t errors "$LOG_FILE"
|
|
323
|
+
|
|
324
|
+
# Multi-word error messages must not be truncated
|
|
325
|
+
assert_output_contains \
|
|
326
|
+
"errors report preserves multi-word message (Connection refused to database)" \
|
|
327
|
+
"Connection refused to database" \
|
|
328
|
+
bash "$LOG_ANALYZER" -t errors "$LOG_FILE"
|
|
329
|
+
|
|
330
|
+
assert_output_contains \
|
|
331
|
+
"errors report preserves multi-word message (Timeout on upstream request)" \
|
|
332
|
+
"Timeout on upstream request" \
|
|
333
|
+
bash "$LOG_ANALYZER" -t errors "$LOG_FILE"
|
|
334
|
+
|
|
335
|
+
# Repeated errors should show correct count (2 for "Connection refused to database")
|
|
336
|
+
assert_output_contains \
|
|
337
|
+
"errors report shows count 2 for repeated error" \
|
|
338
|
+
"Connection refused to database.*2" \
|
|
339
|
+
bash "$LOG_ANALYZER" -t errors "$LOG_FILE"
|
|
340
|
+
|
|
341
|
+
# Output to file
|
|
342
|
+
REPORT="${TEMP_DIR}/report.txt"
|
|
343
|
+
assert_exit_code \
|
|
344
|
+
"output-to-file exits 0" \
|
|
345
|
+
0 \
|
|
346
|
+
bash "$LOG_ANALYZER" -o "$REPORT" "$LOG_FILE"
|
|
347
|
+
|
|
348
|
+
if [[ -f "$REPORT" ]]; then
|
|
349
|
+
pass "report file was created by -o flag"
|
|
350
|
+
else
|
|
351
|
+
fail "report file was not created by -o flag"
|
|
352
|
+
fi
|
|
353
|
+
|
|
354
|
+
assert_output_contains \
|
|
355
|
+
"-o flag prints confirmation message to stdout" \
|
|
356
|
+
"Report saved to" \
|
|
357
|
+
bash "$LOG_ANALYZER" -o "${TEMP_DIR}/report2.txt" "$LOG_FILE"
|
|
358
|
+
|
|
359
|
+
assert_output_not_contains \
|
|
360
|
+
"report file content excludes confirmation message" \
|
|
361
|
+
"Report saved to" \
|
|
362
|
+
cat "$REPORT"
|
|
363
|
+
|
|
364
|
+
# ─── run_ci_checks.sh: determinism and shellcheck gating ───────────────────
|
|
365
|
+
|
|
366
|
+
echo ""
|
|
367
|
+
echo "[run_ci_checks.sh — deterministic validation]"
|
|
368
|
+
|
|
369
|
+
SHELLCHECK_STUB="${TEMP_DIR}/shellcheck-stub.sh"
|
|
370
|
+
cat > "$SHELLCHECK_STUB" <<'EOF'
|
|
371
|
+
#!/usr/bin/env bash
|
|
372
|
+
exit 0
|
|
373
|
+
EOF
|
|
374
|
+
chmod +x "$SHELLCHECK_STUB"
|
|
375
|
+
|
|
376
|
+
assert_exit_code \
|
|
377
|
+
"ci runner --help exits 0" \
|
|
378
|
+
0 \
|
|
379
|
+
bash "$CI_RUNNER" --help
|
|
380
|
+
|
|
381
|
+
assert_exit_code \
|
|
382
|
+
"ci runner succeeds when shellcheck is required and stubbed" \
|
|
383
|
+
0 \
|
|
384
|
+
env SHELLCHECK_BIN="$SHELLCHECK_STUB" \
|
|
385
|
+
bash "$CI_RUNNER" --require-shellcheck --skip-regression-tests
|
|
386
|
+
|
|
387
|
+
assert_exit_code \
|
|
388
|
+
"ci runner fails when required shellcheck is unavailable" \
|
|
389
|
+
1 \
|
|
390
|
+
env SHELLCHECK_BIN="${TEMP_DIR}/missing-shellcheck" \
|
|
391
|
+
bash "$CI_RUNNER" --require-shellcheck --skip-regression-tests
|
|
392
|
+
|
|
393
|
+
assert_output_contains \
|
|
394
|
+
"required-shellcheck failure message is explicit" \
|
|
395
|
+
"shellcheck is required but not available" \
|
|
396
|
+
env SHELLCHECK_BIN="${TEMP_DIR}/missing-shellcheck" \
|
|
397
|
+
bash "$CI_RUNNER" --require-shellcheck --skip-regression-tests
|
|
398
|
+
|
|
399
|
+
assert_exit_code \
|
|
400
|
+
"CI=true defaults to requiring shellcheck" \
|
|
401
|
+
1 \
|
|
402
|
+
env CI=true SHELLCHECK_BIN="${TEMP_DIR}/missing-shellcheck" \
|
|
403
|
+
bash "$CI_RUNNER" --skip-regression-tests
|
|
404
|
+
|
|
405
|
+
# ─── summary ────────────────────────────────────────────────────────────────
|
|
406
|
+
|
|
407
|
+
echo ""
|
|
408
|
+
echo "Results: $PASS passed, $FAIL failed"
|
|
409
|
+
echo ""
|
|
410
|
+
|
|
411
|
+
if [[ $FAIL -gt 0 ]]; then
|
|
412
|
+
exit 1
|
|
413
|
+
fi
|