diff --git a/.github/workflows/appinspect.yaml b/.github/workflows/appinspect.yml similarity index 80% rename from .github/workflows/appinspect.yaml rename to .github/workflows/appinspect.yml index 2dbf92d..acb8603 100644 --- a/.github/workflows/appinspect.yaml +++ b/.github/workflows/appinspect.yml @@ -8,31 +8,35 @@ on: branches: [ main ] paths-ignore: - '**.md' + schedule: + - cron: '25 02 * * THU' workflow_dispatch: jobs: - deploy: + appinspect: + name: App inspect tests runs-on: ubuntu-latest + permissions: + contents: write steps: - name: Checkout uses: actions/checkout@v4 - + - name: Set up Python uses: actions/setup-python@v5 with: python-version: '3.9.16' - + - name: Install Splunk Packaging Toolkit run: | curl https://download.splunk.com/misc/packaging-toolkit/splunk-packaging-toolkit-1.0.1.tar.gz -o /tmp/spl.tar.gz pip install /tmp/spl.tar.gz - + - name: Create Splunk App Package run: | - rm -rf .git .github .gitignore slim package . - cp crowdsec-splunk-app-*.tar.gz /tmp/crowdsec-splunk-app.tar.gz - + mv crowdsec-splunk-app-*.tar.gz /tmp/crowdsec-splunk-app.tar.gz + - name: Retrieve App Inspect Report run: | TOKEN=$(curl -u '${{ secrets.SPLUNKBASE_USERNAME }}:${{ secrets.SPLUNKBASE_PASSWORD }}' --url 'https://api.splunk.com/2.0/rest/login/splunk' | jq -r .data.token) @@ -43,20 +47,21 @@ jobs: -F "app_package=@/tmp/crowdsec-splunk-app.tar.gz" \ --url "https://appinspect.splunk.com/v1/app/validate"| jq -r .links[1].href) REPORT_URL="https://appinspect.splunk.com$REPORT_HREF" - sleep 60 + sleep 30 curl -X GET \ -H "Authorization: bearer $TOKEN" \ - --url $REPORT_URL > /tmp/report - + --url $REPORT_URL > /tmp/report.json + - name: Upload App Inspect Report uses: actions/upload-artifact@v4 with: - name: report - path: /tmp/report - + name: Appinspect Report + path: /tmp/report.json + retention-days: 7 + - name: Check App Inspect Report Results run: | - if grep -q '"result": "failure"' /tmp/report; then + if grep -q '"result": "failure"' /tmp/report.json; then echo "::error::App inspect check failed" exit 1 else diff --git a/.github/workflows/doc-links.yml b/.github/workflows/doc-links.yml new file mode 100644 index 0000000..a605909 --- /dev/null +++ b/.github/workflows/doc-links.yml @@ -0,0 +1,39 @@ +name: Documentation links + +on: + push: + branches: [ main ] + pull_request: + branches: [ main ] + workflow_dispatch: + +permissions: + contents: read + +jobs: + markdown-test: + name: Markdown files test + runs-on: ubuntu-latest + steps: + + - name: Clone sources + uses: actions/checkout@v4 + with: + path: extension + + - name: Launch localhost server + run: | + sudo npm install --global http-server + http-server ./extension & + + - name: Set up Ruby 2.6 + uses: ruby/setup-ruby@v1 + with: + ruby-version: 2.6 + + - name: Check links in Markdown files + run: | + gem install awesome_bot + cd extension + awesome_bot --files README.md --allow-dupe --allow-redirect --allow 401 --skip-save-results --base-url http://localhost:8080/ + awesome_bot dev/*.md --allow-dupe --allow-redirect --allow 401 --white-list http://localhost:8000 --skip-save-results --base-url http://localhost:8080/dev/ diff --git a/.github/workflows/keepalive.yml b/.github/workflows/keepalive.yml new file mode 100644 index 0000000..8d55036 --- /dev/null +++ b/.github/workflows/keepalive.yml @@ -0,0 +1,25 @@ +name: Keep Alive +on: + + schedule: + - cron: '0 3 * * 4' + +permissions: + actions: write + +jobs: + keep-alive: + + name: Keep Alive + runs-on: ubuntu-latest + + steps: + + - name: Clone project files + uses: actions/checkout@v4 + + # keepalive-workflow keeps GitHub from turning off tests after 60 days + - uses: gautamkrishnar/keepalive-workflow@v2 + with: + time_elapsed: 40 + workflow_files: 'appinspect.yml' diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml deleted file mode 100644 index afd6f6b..0000000 --- a/.github/workflows/release.yaml +++ /dev/null @@ -1,35 +0,0 @@ -# release workflow - -name: Release -on: - release: - -jobs: - deploy: - - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - name: Set up Python - uses: actions/setup-python@v5 - with: - python-version: '3.9.16' - - name: Install splunk toolkit - run: | - curl https://download.splunk.com/misc/packaging-toolkit/splunk-packaging-toolkit-1.0.1.tar.gz -o /tmp/spl.tar.gz - pip install /tmp/spl.tar.gz - - name: Make package - run: | - rm -rf .git .github .gitignore - slim package . - cp crowdsec-splunk-app-*.tar.gz ./crowdsec-splunk-app.tar.gz - - - name: Upload to SplunkBase - run: | - curl -u "${{ secrets.SPLUNKBASE_USERNAME }}:${{ secrets.SPLUNKBASE_PASSWORD }}" --request POST \ - "https://splunkbase.splunk.com/api/v1/app/6800/new_release/" \ - -F "files[]=@crowdsec-splunk-app.tar.gz" \ - -F "filename=crowdsec-splunk-app.tar.gz" \ - -F "cim_versions=5.x" \ - -F "splunk_versions=9.0" \ - -F "visibility=true" \ No newline at end of file diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..54c2cd1 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,146 @@ +name: Create release +# example: gh workflow run release.yml -f tag_name=v1.1.4 +on: + workflow_dispatch: + inputs: + tag_name: + type: string + required: true + description: Tag name with v prefix + publish-to-splunkbase: + type: boolean + description: Publish to Splunkbase + default: true + +jobs: + create-release: + + name: Create release + runs-on: ubuntu-latest + permissions: + contents: write + env: + PACKAGE_NAME: "crowdsec-splunk-app.tar.gz" + + steps: + - name: Check naming convention + run: | + VERIF=$(echo ${{ github.event.inputs.tag_name }} | grep -E "^v([0-9]{1,}\.)([0-9]{1,}\.)([0-9]{1,})(-(alpha|beta)\.[0-9]{1,})?$") + if [ ! ${VERIF} ] + then + echo "Tag name '${{ github.event.inputs.tag_name }}' does not comply with naming convention vX.Y.Z" + exit 1 + fi + - name: Set version number without v + run: | + echo "VERSION_NUMBER=$(echo ${{ github.event.inputs.tag_name }} | sed 's/v//g' )" >> $GITHUB_ENV + + - name: Clone sources + uses: actions/checkout@v4 + + - name: Check version ${{ env.VERSION_NUMBER }} consistency in files + # CHANGELOG.md, app.manifest, default/app.conf + run: | + # Check top ## [VERSION_NUMBER](GITHUB_URL/releases/tag/vVERSION_NUMBER) - yyyy-mm-dd in CHANGELOG.md + # Example: ## [0.0.2](https://github.com/crowdsecurity/crowdsec-splunk-app/releases/tag/v0.0.2) - 2024-02-07 + CURRENT_DATE=$(date +'%Y-%m-%d') + echo $CURRENT_DATE + CHANGELOG_VERSION=$(grep -o -E "## \[(.*)\].* - $CURRENT_DATE" CHANGELOG.md | head -1 | sed 's/ //g') + echo $CHANGELOG_VERSION + if [[ $CHANGELOG_VERSION == "##[${{ env.VERSION_NUMBER }}]($GITHUB_SERVER_URL/$GITHUB_REPOSITORY/releases/tag/v${{ env.VERSION_NUMBER }})-$CURRENT_DATE" ]] + then + echo "CHANGELOG VERSION OK" + else + echo "CHANGELOG VERSION KO" + echo $CHANGELOG_VERSION + exit 1 + fi + # Check top [_Compare with previous release_](GITHUB_URL/compare/vLAST_TAG...vVERSION_NUMBER) in CHANGELOG.md + # Example: [_Compare with previous release_](https://github.com/crowdsecurity/crowdsec-splunk-app/compare/v0.0.1...v0.0.2) + COMPARISON=$(grep -oP "$GITHUB_SERVER_URL/$GITHUB_REPOSITORY/compare/\K(.*)$" CHANGELOG.md | head -1) + LAST_TAG=$(curl -Ls -o /dev/null -w %{url_effective} $GITHUB_SERVER_URL/$GITHUB_REPOSITORY/releases/latest | grep -oP "\/tag\/\K(.*)$") + if [[ $COMPARISON == "$LAST_TAG...v${{ env.VERSION_NUMBER }})" ]] + then + echo "VERSION COMPARISON OK" + else + echo "VERSION COMPARISON KO" + echo $COMPARISON + echo "$LAST_TAG...v${{ env.VERSION_NUMBER }})" + exit 1 + fi + # Check in app.manifest + # Example: "version": "0.0.2" + MANIFEST_VERSION=$(grep -oP '"version": "\K(.*)(?=")' app.manifest | head -1) + if [[ $MANIFEST_VERSION == "${{ env.VERSION_NUMBER }}" ]] + then + echo "MANIFEST VERSION OK" + else + echo "MANIFEST VERSION KO" + echo $MANIFEST_VERSION + exit 1 + fi + # Check in default/app.conf + # Example: version=1.0.6 + APP_CONF_VERSION=$(sed -n 's/^version=\(.*\)/\1/p' default/app.conf | tr -d '\r' ) + if [[ $APP_CONF_VERSION == "${{ env.VERSION_NUMBER }}" ]] + then + echo "app.conf VERSION OK" + else + echo "app.conf VERSION KO" + echo $APP_CONF_VERSION + exit 1 + fi + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: '3.9.16' + + - name: Install splunk toolkit + run: | + curl https://download.splunk.com/misc/packaging-toolkit/splunk-packaging-toolkit-1.0.1.tar.gz -o /tmp/spl.tar.gz + pip install /tmp/spl.tar.gz + + - name: Make package + run: | + # @see https://dev.splunk.com/enterprise/reference/packagingtoolkit/packagingtoolkitcli/ + slim package . + cp crowdsec-splunk-app-*.tar.gz ./${{ env.PACKAGE_NAME }} + + - name: Create Tag ${{ github.event.inputs.tag_name }} + uses: actions/github-script@v7 + with: + github-token: ${{ github.token }} + script: | + github.rest.git.createRef({ + owner: context.repo.owner, + repo: context.repo.repo, + ref: "refs/tags/${{ github.event.inputs.tag_name }}", + sha: context.sha + }) + + - name: Prepare release notes + run: | + # Retrieve release body and remove --- + VERSION_RELEASE_NOTES=$(awk -v ver="[${{ env.VERSION_NUMBER }}]($GITHUB_SERVER_URL/$GITHUB_REPOSITORY/releases/tag/v${{ env.VERSION_NUMBER }})" '/^## / { if (p) { exit }; if ($2 == ver) { p=1; next} } p && NF' CHANGELOG.md | sed ':a;N;$!ba;s/\n---/ /g') + echo "$VERSION_RELEASE_NOTES" >> CHANGELOG.txt + + - name: Create release ${{ env.VERSION_NUMBER }} + uses: softprops/action-gh-release@v2 + with: + files: ${{ env.PACKAGE_NAME }} + body_path: CHANGELOG.txt + name: ${{ env.VERSION_NUMBER }} + tag_name: ${{ github.event.inputs.tag_name }} + + + - name: Upload to SplunkBase + if: github.event.inputs.publish-to-splunkbase == 'true' + run: | + curl -u "${{ secrets.SPLUNKBASE_USERNAME }}:${{ secrets.SPLUNKBASE_PASSWORD }}" --request POST \ + "https://splunkbase.splunk.com/api/v1/app/6800/new_release/" \ + -F "files[]=@${{ env.PACKAGE_NAME }}" \ + -F "filename=${{ env.PACKAGE_NAME }}" \ + -F "cim_versions=5.x" \ + -F "splunk_versions=9.0" \ + -F "visibility=true" \ No newline at end of file diff --git a/.gitignore b/.gitignore index 06ae7d1..ed4c918 100644 --- a/.gitignore +++ b/.gitignore @@ -33,6 +33,8 @@ MANIFEST # Usually these files are written by a python script from a template # before PyInstaller builds the exe, so as to inject date/other infos into it. *.manifest +# app.manifest is a created by "slim generate-manifest . --output=app.manifest" +!app.manifest *.spec # Installer logs diff --git a/README.md b/README.md index b8b7b4a..26d342b 100644 --- a/README.md +++ b/README.md @@ -20,4 +20,6 @@ The following command is used to run an IP check through the CrowdSec's CTI API' - It denotes the field name where the IP address is stored in the index. ## Results -On the event of clicking the `Search` button, users will be able to view a brief overview of various fields associated with the input IP address. This includes but not limited to location, behaviors, classifications, attack details – name, label, description, references followed by scores, threats, etc. +On the event of clicking the `Search` button, users will be able to view a brief overview of various fields associated with the input IP address. + +This includes but not limited to location, behaviors, classifications, attack details – name, label, description, references followed by scores, threats, etc. diff --git a/app.manifest b/app.manifest new file mode 100644 index 0000000..27ed0f1 --- /dev/null +++ b/app.manifest @@ -0,0 +1,94 @@ +{ + "schemaVersion": "2.0.0", + "info": { + "title": "CrowdSec", + "id": { + "group": null, + "name": "crowdsec-splunk-app", + "version": "1.1.0" + }, + "author": [ + { + "name": "CrowdSec", + "email": "integrations-ssa@crowdsec.net", + "company": "CrowdSec" + } + ], + "releaseDate": null, + "description": "This app leverages the CrowdSec's CTI API to perform lookups on IPs", + "classification": { + "intendedAudience": null, + "categories": [], + "developmentStatus": null + }, + "commonInformationModels": null, + "license": { + "name": null, + "text": null, + "uri": null + }, + "privacyPolicy": { + "name": null, + "text": null, + "uri": null + }, + "releaseNotes": { + "name": null, + "text": "./README.md", + "uri": null + } + }, + "dependencies": null, + "tasks": null, + "inputGroups": null, + "incompatibleApps": null, + "platformRequirements": null, + "supportedDeployments": [ + "_standalone", + "_distributed" + ], + "targetWorkloads": null +} +# The following sections can be customized and added to the manifest. For detailed information, +# see the documentation at http://dev.splunk.com/view/packaging-toolkit/SP-CAAAE9V +# +# Lists the app dependencies and version requirements +# "dependencies": { +# ":": { +# "version": "*", +# "package": "", +# "optional": [true|false] +# } +# } +# +# Lists the inputs that belong on the search head rather than forwarders +# "tasks": [] +# +# Lists the possible input groups with app dependencies, and inputs that should be included +# "inputGroups": { +# "": { +# "requires": { +# ":": [""] +# }, +# "inputs": [""] +# } +# } +# +# Lists the app IDs that cannot be installed on the system alongside this app +# "incompatibleApps": { +# ":": "" +# } +# +# Specify the platform version requirements for this app +# "platformRequirements": { +# "splunk": { +# "Enterprise": "" +# } +# } +# +# Lists the supported deployment types this app can be installed on +# "supportedDeployments": ["*" | "_standalone" | "_distributed" | "_search_head_clustering"] +# +# Lists the targets where app can be installed to +# "targetWorkloads": ["*" | "_search_heads" | "_indexers" | "_forwarders"] +# diff --git a/default/app.conf b/default/app.conf index 0491cef..c864f48 100644 --- a/default/app.conf +++ b/default/app.conf @@ -17,7 +17,7 @@ label = CrowdSec [launcher] author=CrowdSec description=This app leverages the CrowdSec's CTI API to perform lookups on IPs -version=1.0.6 +version=1.1.0 [package] id = crowdsec-splunk-app diff --git a/dev/README.md b/dev/README.md index e88f25a..56982e7 100644 --- a/dev/README.md +++ b/dev/README.md @@ -13,6 +13,9 @@ - [Some resources for developers](#some-resources-for-developers) - [Update documentation table of contents](#update-documentation-table-of-contents) - [Release process](#release-process) + - [Splunk SDK](#splunk-sdk) + - [Final check](#final-check) + - [Create a release](#create-a-release) @@ -108,6 +111,8 @@ doctoc dev/README.md --maxlevel 4 ## Release process +### Splunk SDK + Before releasing a new version, ensure that you have updated the Splunk SDK to the latest version. You can do this by running the following command: @@ -116,4 +121,31 @@ You can do this by running the following command: make add-sdk ``` +### Final check + +We use [Semantic Versioning](https://semver.org/spec/v2.0.0.html) approach to determine the next version number of the SDK. + +Once you are ready to release a new version (e.g. when all your changes are on the `main` branch), you should: + +- Determine the next version number based on the changes made since the last release: `MAJOR.MINOR.PATCH` +- Update the [CHANGELOG.md](../CHANGELOG.md) file with the new version number and the changes made since the last release. + - Each release description must respect the same format as the previous ones. +- Update the `default/app.conf` file with the new version number. +- Update the `app.manifest` file with the new version number by running the following command in the root folder of the project: + +```bash +slim generate-manifest . --output=app.manifest +``` + + +- Commit the changes with a message like `feat(*) Prepare release MAJOR.MINOR.PATCH`. + +### Create a release + +- Browse to the [GitHub `Create and publish release` action](https://github.com/crowdsecurity/crowdsec-splunk-app/actions/workflows/release.yml) + - Click on `Run workflow` and fill the `Tag name` input with the new version number prefixed by a `v`: `vMAJOR.MINOR.PATCH`. + - Tick the `Publish to Splunkbase` checkbox. + - Click on `Run workflow` to trigger the release process. + +