Compare commits
No commits in common. "main" and "fix-go-revert" have entirely different histories.
main
...
fix-go-rev
|
|
@ -1,98 +0,0 @@
|
|||
# syntax=docker/dockerfile:1
|
||||
|
||||
# =============================================================================
|
||||
# Stage 1: Base tools installation (rarely changes, excellent caching)
|
||||
# =============================================================================
|
||||
FROM mcr.microsoft.com/devcontainers/go:1-1.23 as tools
|
||||
|
||||
# Install system packages in single layer for better caching
|
||||
RUN sudo apt update && sudo apt install -y \
|
||||
nodejs \
|
||||
lsb-release \
|
||||
curl \
|
||||
gpg \
|
||||
protobuf-compiler \
|
||||
git-lfs \
|
||||
&& sudo apt-get clean \
|
||||
&& sudo rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Install Go tools (these rarely change), separately to avoid memory issues
|
||||
RUN export GOMAXPROCS=1 && go install google.golang.org/protobuf/cmd/protoc-gen-go@v1.34.1
|
||||
RUN export GOMAXPROCS=1 && go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@v1.3.0
|
||||
|
||||
ENV PATH="${PATH}:$(go env GOPATH)/bin"
|
||||
|
||||
# =============================================================================
|
||||
# Stage 2: External services installation (moderate caching)
|
||||
# =============================================================================
|
||||
FROM tools as services
|
||||
|
||||
ARG TARGETARCH
|
||||
|
||||
# Install redis
|
||||
RUN curl -fsSL https://packages.redis.io/gpg | sudo gpg --dearmor -o /usr/share/keyrings/redis-archive-keyring.gpg && \
|
||||
sudo chmod 644 /usr/share/keyrings/redis-archive-keyring.gpg && \
|
||||
echo "deb [signed-by=/usr/share/keyrings/redis-archive-keyring.gpg] https://packages.redis.io/deb $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/redis.list && \
|
||||
sudo apt-get update -y && \
|
||||
sudo apt-get install redis -y && \
|
||||
sudo apt-get clean && \
|
||||
sudo rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Install gcloud and kubectl
|
||||
RUN echo "deb [signed-by=/usr/share/keyrings/cloud.google.gpg] https://packages.cloud.google.com/apt cloud-sdk main" | tee -a /etc/apt/sources.list.d/google-cloud-sdk.list && \
|
||||
curl https://packages.cloud.google.com/apt/doc/apt-key.gpg | gpg --dearmor -o /usr/share/keyrings/cloud.google.gpg && \
|
||||
sudo apt-get update && \
|
||||
sudo apt-get install -y \
|
||||
google-cloud-cli \
|
||||
kubectl \
|
||||
google-cloud-cli-gke-gcloud-auth-plugin \
|
||||
&& sudo apt-get clean \
|
||||
&& sudo rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Install binary tools with architecture support
|
||||
RUN curl -fsSL https://raw.githubusercontent.com/metalbear-co/mirrord/main/scripts/install.sh | bash
|
||||
|
||||
# Install yq with architecture detection
|
||||
RUN curl -Lo /usr/local/bin/yq https://github.com/mikefarah/yq/releases/download/v4.34.1/yq_linux_${TARGETARCH} && \
|
||||
sudo chmod +x /usr/local/bin/yq
|
||||
|
||||
# Configure Go to handle private modules
|
||||
RUN go env -w GOPRIVATE=$(go env GOPRIVATE),git0.harness.io
|
||||
|
||||
# =============================================================================
|
||||
# Stage 3: Code preparation and build (secure - credentials cleaned in same layer)
|
||||
# =============================================================================
|
||||
FROM services as builder
|
||||
|
||||
ARG BRANCH
|
||||
|
||||
# Arg to track commit hash — cache busts only when this changes
|
||||
ARG COMMIT_SHA
|
||||
|
||||
WORKDIR /root
|
||||
|
||||
RUN --mount=type=secret,id=harness_code_secret_harness0,env=HARNESS_CODE_SECRET_HARNESS0 \
|
||||
--mount=type=secret,id=harness_code_user,env=HARNESS_CODE_USER \
|
||||
--mount=type=secret,id=github_secret,env=GITHUB_SECRET \
|
||||
--mount=type=secret,id=github_user,env=GITHUB_USER \
|
||||
echo $COMMIT_SHA > /commit.txt && \
|
||||
git config --global credential.helper store && \
|
||||
echo "https://${HARNESS_CODE_USER}:${HARNESS_CODE_SECRET_HARNESS0}@git0.harness.io" >> ~/.git-credentials && \
|
||||
echo "https://${GITHUB_USER}:${GITHUB_SECRET}@github.com" >> ~/.git-credentials && \
|
||||
echo "@harness:registry=https://npm.pkg.github.com" > ~/.npmrc && \
|
||||
echo "//npm.pkg.github.com/:_authToken=${GITHUB_SECRET}" >> ~/.npmrc && \
|
||||
echo "always-auth=true" >> ~/.npmrc && \
|
||||
echo "machine git0.harness.io login git password ${HARNESS_CODE_SECRET_HARNESS0}" >> ~/.netrc && \
|
||||
git clone -b ${BRANCH} https://git0.harness.io/l7B_kbSEQD2wjrM7PShm5w/PROD/Harness_Commons/gitness.git && \
|
||||
cd /root/gitness && \
|
||||
git lfs install && git lfs pull && \
|
||||
make init && \
|
||||
make dep && \
|
||||
make tools && \
|
||||
make web-build && \
|
||||
make build && \
|
||||
rm -f ~/.git-credentials && git config --global --unset credential.helper && \
|
||||
sed -i 's|//npm.pkg.github.com/:_authToken=.*|//npm.pkg.github.com/:_authToken=xxx|' ~/.npmrc && \
|
||||
sed -i '/machine git0\.harness\.io/d' ~/.netrc
|
||||
|
||||
WORKDIR /root/gitness
|
||||
|
|
@ -1,19 +0,0 @@
|
|||
{
|
||||
"image": "harness0.harness.io/oci/gitspaces-image-registry/gitness-base:main-amd64",
|
||||
"remoteUser": "root",
|
||||
"forwardPorts": [
|
||||
"3000"
|
||||
],
|
||||
"customizations": {
|
||||
"harnessGitspaces": {
|
||||
"connectors": [
|
||||
{
|
||||
"type": "DockerRegistry",
|
||||
"identifier": "org.gitspacesimageregistry"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"postCreateCommand": "sudo chmod +x /root/gitness/.devcontainer/postCreate.sh && /root/gitness/.devcontainer/postCreate.sh",
|
||||
"postStartCommand": "sudo chmod +x /root/gitness/.devcontainer/postStart.sh && /root/gitness/.devcontainer/postStart.sh"
|
||||
}
|
||||
|
|
@ -1,2 +0,0 @@
|
|||
#!/bin/sh
|
||||
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
#!/bin/sh
|
||||
|
||||
#sudo service redis-server start
|
||||
redis-server &
|
||||
|
||||
|
|
@ -1,12 +1,2 @@
|
|||
*.sqlite
|
||||
*.sqlite3
|
||||
web/node_modules
|
||||
web/dist
|
||||
release
|
||||
.idea
|
||||
coverage.out
|
||||
*.rsa
|
||||
*.rsa.pub
|
||||
|
||||
# ignore any executables we build
|
||||
/gitness
|
||||
*
|
||||
!release/*
|
||||
|
|
|
|||
|
|
@ -0,0 +1,107 @@
|
|||
---
|
||||
kind: pipeline
|
||||
type: docker
|
||||
name: linux-amd64
|
||||
|
||||
platform:
|
||||
arch: amd64
|
||||
os: linux
|
||||
|
||||
steps:
|
||||
- name: test
|
||||
image: golang:1.22.7
|
||||
commands:
|
||||
- go test -race ./...
|
||||
- go build -o /dev/null github.com/drone/drone/cmd/drone-server
|
||||
- go build -o /dev/null -tags "oss nolimit" github.com/drone/drone/cmd/drone-server
|
||||
|
||||
- name: build
|
||||
image: golang:1.22.7
|
||||
commands:
|
||||
- sh scripts/build.sh
|
||||
environment:
|
||||
GOARCH: amd64
|
||||
GOOS: linux
|
||||
|
||||
- name: publish
|
||||
image: plugins/docker:18
|
||||
settings:
|
||||
auto_tag: true
|
||||
auto_tag_suffix: linux-amd64
|
||||
dockerfile: docker/Dockerfile.server.linux.amd64
|
||||
repo: drone/drone
|
||||
username:
|
||||
from_secret: docker_username
|
||||
password:
|
||||
from_secret: docker_password
|
||||
when:
|
||||
event:
|
||||
- push
|
||||
- tag
|
||||
|
||||
---
|
||||
kind: pipeline
|
||||
type: vm
|
||||
name: linux-arm64
|
||||
|
||||
pool:
|
||||
use: ubuntu_arm64
|
||||
|
||||
platform:
|
||||
arch: arm64
|
||||
os: linux
|
||||
|
||||
steps:
|
||||
- name: build
|
||||
image: golang:1.22.7
|
||||
commands:
|
||||
- sh scripts/build.sh
|
||||
environment:
|
||||
GOARCH: arm64
|
||||
GOOS: linux
|
||||
|
||||
- name: publish
|
||||
image: plugins/docker:18
|
||||
settings:
|
||||
auto_tag: true
|
||||
auto_tag_suffix: linux-arm64
|
||||
dockerfile: docker/Dockerfile.server.linux.arm64
|
||||
repo: drone/drone
|
||||
username:
|
||||
from_secret: docker_username
|
||||
password:
|
||||
from_secret: docker_password
|
||||
|
||||
trigger:
|
||||
event:
|
||||
- push
|
||||
- tag
|
||||
|
||||
depends_on:
|
||||
- linux-amd64
|
||||
|
||||
---
|
||||
kind: pipeline
|
||||
type: docker
|
||||
name: manifest
|
||||
|
||||
steps:
|
||||
- name: publish
|
||||
image: plugins/manifest:1.2
|
||||
settings:
|
||||
auto_tag: true
|
||||
ignore_missing: true
|
||||
spec: docker/manifest.server.tmpl
|
||||
username:
|
||||
from_secret: docker_username
|
||||
password:
|
||||
from_secret: docker_password
|
||||
|
||||
trigger:
|
||||
event:
|
||||
- push
|
||||
- tag
|
||||
|
||||
depends_on:
|
||||
- linux-arm64
|
||||
|
||||
|
|
@ -1,68 +0,0 @@
|
|||
#!/bin/bash
|
||||
# Copyright 2025 Harness Inc. All rights reserved.
|
||||
# Use of this source code is governed by the PolyForm Free Trial 1.0.0 license
|
||||
# that can be found in the licenses directory at the root of this repository, also available at
|
||||
# https://polyformproject.org/wp-content/uploads/2020/05/PolyForm-Free-Trial-1.0.0.txt.
|
||||
|
||||
###################################################
|
||||
# Purpose
|
||||
# The purpose of this script is to facilitate auto-tagging of
|
||||
# Jira tickets with fix-versions. There are two tricky parts to auto-tagging:
|
||||
#
|
||||
# 1. Given a change set (PR diff), what constitutes a change to a service?
|
||||
# 2. Given you've determined a set of files has changed a service, which service was changed?
|
||||
#
|
||||
# This script endeavors to answer question number one - which files constitute a change to a service
|
||||
# Given an input file which is the git diff from a PR
|
||||
# this script should determine what file changes in the diff
|
||||
# constitute a material change to a service. At the time
|
||||
# of this writing, this currently only identifies java and go
|
||||
# files, and if those files are in the change list, then those
|
||||
# file names are returned in the output file.
|
||||
#
|
||||
# Inputs
|
||||
# $1 - File containing unique changed files
|
||||
# $2 - the output file which should ultimately contain file names from the diff that affect a service
|
||||
#
|
||||
# See BT-10437 for more information
|
||||
#
|
||||
# Called by https://harness0.harness.io/ng/account/l7B_kbSEQD2wjrM7PShm5w/all/orgs/Audit/projects/Engops_Audit/pipelines/PRMergedGithub/pipeline-studio/?storeType=INLINE
|
||||
# Unlike other scripts for detecting changes, this one doesn't receive a git diff, rather a unique list of files changed by the git update.
|
||||
#
|
||||
# Owner: Engops
|
||||
# Author: Marc Batchelor
|
||||
###################################################
|
||||
echo "Arguments: " $*
|
||||
uniqueFileNamesFile=$1
|
||||
sourceDiffNames=$2
|
||||
if [ -z "$uniqueFileNamesFile" ]; then
|
||||
echo "Missing input PR Difference file."
|
||||
exit 1
|
||||
fi
|
||||
if [ ! -f "$uniqueFileNamesFile" ]; then
|
||||
echo "Input file $uniqueFileNamesFile does not exist and is required."
|
||||
exit 2
|
||||
fi
|
||||
if [ -z "$sourceDiffNames" ]; then
|
||||
echo "Missing output file."
|
||||
exit 3
|
||||
fi
|
||||
if [ ! -f "$sourceDiffNames" ]; then
|
||||
echo "File $sourceDiffNames does not exist and is required."
|
||||
exit 4
|
||||
fi
|
||||
|
||||
##### Detect git diff file, or processed filenames only
|
||||
isDiffFile=$(grep -E "^diff --git a\/" "$uniqueFileNamesFile" | wc -l)
|
||||
if [ $isDiffFile -gt 0 ]; then
|
||||
echo "Received a diff file... fix it to be a filenames only file"
|
||||
fileNamesOnlyVar=$(cat "$uniqueFileNamesFile"|grep -E "^diff --git" | sed 's/diff --git a\///' | sed 's/ b\/.*$//' | sort -u)
|
||||
echo -e "$fileNamesOnlyVar">"$uniqueFileNamesFile"
|
||||
fi
|
||||
|
||||
# Java files (and other files) which end up in jars - these are kept in .../src/main/x/x/x/*
|
||||
cat "$uniqueFileNamesFile" | grep -E ".*.java$" | grep -v "/test/" > $sourceDiffNames
|
||||
# go files (without tests)
|
||||
cat "$uniqueFileNamesFile" | grep -E ".*.go$|.*.mod$" | grep -v "test_" >> $sourceDiffNames
|
||||
# Other source files
|
||||
cat "$uniqueFileNamesFile" | grep -E ".*.(Dockerfile|Dockerfile.cov|Dockerfile.dev|bazel|c|cc|conf|css|ejs|eslintrc|gitmodules|go|golang|gradle|gv|graphql|h|html|iml|js|json|less|mod|pipeline|mustache|pl|png|properties|ps1|proto|py|pyc|qbg|repo|rs|sh||sha256|sql|sum|svg|tf|tgz|tmpl|tpl|ts|tsx|xml|yaml|yml)$" >> $sourceDiffNames
|
||||
|
|
@ -1,38 +0,0 @@
|
|||
#!/usr/bin/env sh
|
||||
|
||||
echo Running pre-commit hook
|
||||
|
||||
# Check for required binaries, otherwise don't run
|
||||
if ! command -v grep &> /dev/null
|
||||
then
|
||||
echo "grep could not be found - skipping pre-commit"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if ! command -v sed &> /dev/null
|
||||
then
|
||||
echo "sed could not be found - skipping pre-commit"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if ! command -v xargs &> /dev/null
|
||||
then
|
||||
echo "xargs could not be found - skipping pre-commit"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Run pre-commit, this checks if we changed any golang files and runs the checks.
|
||||
# The files are then git-added
|
||||
FILES=$(git diff --cached --name-only --diff-filter=ACMR | grep .go | sed 's| |\\ |g')
|
||||
if [ -n "$FILES" ]; then
|
||||
make format
|
||||
make lint
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Error running make check - please fix before committing"
|
||||
echo "if this is a mistake you can skip the checks with 'git commit --no-verify'"
|
||||
exit 1
|
||||
fi
|
||||
echo "$FILES" | xargs git add
|
||||
fi
|
||||
|
||||
exit 0
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
## Drone Community Code of Conduct
|
||||
|
||||
Drone follows the [CNCF Code of Conduct](https://github.com/cncf/foundation/blob/master/code-of-conduct.md).
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
# Contributing
|
||||
|
||||
Please take a moment to review this document in order to make the contribution process easy and effective for everyone involved.
|
||||
|
||||
Following these guidelines helps to communicate that you respect the time of the developers maintaining this project. In return, they should reciprocate that respect in addressing your issue or assessing patches and features.
|
||||
|
||||
## Support Requests
|
||||
|
||||
The [mailing list](https://discourse.drone.io) is the preferred channel for support requests. Please do not use the issue tracker for personal support requests.
|
||||
|
||||
## Feature Requests
|
||||
|
||||
Feature requests are welcome. But take a moment to find out whether your idea fits with the scope and aims of this project. It is up to you to make a strong case to convince the developers of the merits of this feature. Please provide as much detail and context as possible.
|
||||
|
||||
## Compatibility
|
||||
|
||||
This project maintains a strong commitment to backward compatibility. Changing the runtime behavior or configuration in a manner that breaks the public contract should always be avoided.
|
||||
|
||||
## Dependencies
|
||||
|
||||
This project does not attempt to track the latest version for each dependency. Please only apply the minimal dependency changes required for your patch to work. _If it ain't broke, don't fix it._
|
||||
|
||||
## Pull Requests
|
||||
|
||||
Please discuss on our [mailing list](https://discourse.drone.io) before embarking on any significant pull request, otherwise you risk spending time working on something the developers might not want to merge into the project.
|
||||
|
||||
Pull requests should remain focused in scope and avoid containing unrelated commits. For example, a pull request could add a feature, fix a bug, or format code; but not a mixture.
|
||||
|
||||
When you are ready to submit a pull request you can use the below checklist to to increase the likelihood of your pull request being accepted in a timely manner:
|
||||
|
||||
- Run the unit tests.
|
||||
- Format the code.
|
||||
- Include entry in [CHANGELOG.md](../CHANGELOG.md) that describes the change.
|
||||
- Include unit tests when you contribute a new feature.
|
||||
- Include unit tests when you contribute a bug fix to prevent regressions.
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
<!-- PLEASE READ BEFORE DELETING
|
||||
|
||||
Bugs or Issues? Please create a new topic in our Discourse forum.
|
||||
We are migrating all Drone repositories to Discourse for bug tracking.
|
||||
New GitHub issues may be automatically deleted.
|
||||
|
||||
https://community.harness.io/
|
||||
https://community.harness.io/c/bugs/17
|
||||
https://community.harness.io/c/ideas/11
|
||||
|
||||
Failing Builds? Please do not use GitHub issues for generic support
|
||||
questions. Instead please use Stack Overflow:
|
||||
|
||||
http://stackoverflow.com/questions/tagged/drone.io
|
||||
|
||||
-->
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
## Commit Checklist
|
||||
|
||||
Thank you for creating a pull request! To help us review / merge this can you make sure that your PR adheres as much as possible to the following.
|
||||
|
||||
### The Basics
|
||||
|
||||
- Commit is a single logical unit of work, only use multiple commits if doing different tasks
|
||||
- Commit does not include commented out code or unneeded files
|
||||
- rebase of main branch
|
||||
|
||||
### The Content
|
||||
|
||||
- Must include testing for bug or feature
|
||||
- Must include appropriate documentation changes if it is introducing a new feature or changing existing functionality
|
||||
- Must pass existing test suites
|
||||
|
||||
### The Commit Message
|
||||
|
||||
- Short meaningful description (ex: remove deprecated steps)
|
||||
- Uses the imperative, present tense: "change", not "changed" or "changes"
|
||||
- Includes motivation for the change, and contrasts its implementation with the previous behavior
|
||||
|
||||
### The Pull Request
|
||||
|
||||
- What is the reason for this change
|
||||
- Example usage of the failure for a bug, or configuration and expected output for a feature
|
||||
- Steps to test the change
|
||||
|
|
@ -0,0 +1,122 @@
|
|||
# [Drone](https://www.drone.io/) <img src="https://github.com/drone/brand/blob/master/screenshots/screenshot_build_success.png" style="max-width:100px;" />
|
||||
**Welcome to the Drone codebase, we are thrilled to have you here!**
|
||||
|
||||
## What is Drone?
|
||||
Drone is a continuous delivery system built on container technology. Drone uses a simple YAML build file, to define and execute build pipelines inside Docker containers.
|
||||
|
||||
## Table of Contents
|
||||
|
||||
- [What is Drone?](#what-is-drone)
|
||||
- [Table of Contents](#table-of-contents)
|
||||
- [Community and Support](#community-and-support)
|
||||
- [Contributing](#contributing)
|
||||
- [Code of Conduct](#code-of-conduct)
|
||||
- [Setup Documentation](#setup-documentation)
|
||||
- [Usage Documentation](#usage-documentation)
|
||||
- [Example `.drone.yml` build file](#example-droneyml-build-file)
|
||||
- [Plugin Index](#plugin-index)
|
||||
- [Documentation and Other Links](#documentation-and-Other-Links)
|
||||
|
||||
## Community and Support
|
||||
[Harness Community Slack](https://join.slack.com/t/harnesscommunity/shared_invite/zt-y4hdqh7p-RVuEQyIl5Hcx4Ck8VCvzBw) - Join the #drone slack channel to connect with our engineers and other users running Drone CI.
|
||||
</br>
|
||||
[Harness Community Forum](https://community.harness.io/) - Ask questions, find answers, and help other users.
|
||||
</br>
|
||||
[Report A Bug](https://community.harness.io/c/bugs/17) - Find a bug? Please report in our forum under Drone Bugs. Please provide screenshots and steps to reproduce.
|
||||
</br>
|
||||
[Events](https://www.meetup.com/harness/) - Keep up to date with Drone events and check out previous events [here](https://www.youtube.com/watch?v=Oq34ImUGcHA&list=PLXsYHFsLmqf3zwelQDAKoVNmLeqcVsD9o).
|
||||
|
||||
## Contributing
|
||||
|
||||
We encourage you to contribute to Drone! Whether that's joining in on the community slack or discourse, or contributing pull requests / documentation changes or raising issues.
|
||||
|
||||
## Code of Conduct
|
||||
|
||||
Drone follows the [CNCF Code of Conduct](https://github.com/cncf/foundation/blob/master/code-of-conduct.md).
|
||||
|
||||
### Setup Documentation
|
||||
|
||||
This section of the [documentation](http://docs.drone.io/installation/) will help you install and configure the Drone Server and one or many Runners. A runner is a standalone daemon that polls the server for pending pipelines to execute.
|
||||
|
||||
### Usage Documentation
|
||||
|
||||
Our [documentation](http://docs.drone.io/getting-started/) can help you get started with the different types of pipelines/builds. There are different runners / plugins / extensions designed for different use cases to help make an efficient and simple build pipeline
|
||||
|
||||
### Plugin Index
|
||||
|
||||
Plugins are used in build steps to perform actions, eg send a message to slack or push a container to a registry. We have an extensive list of community plugins to customize your build pipeline, you can find those [here](http://plugins.drone.io/).
|
||||
|
||||
### Example `.drone.yml` build file.
|
||||
|
||||
This build file contains a single pipeline (you can have multiple pipelines too) that builds a go application. The front end with npm. Publishes the docker container to a registry and announces the results to a slack room.
|
||||
|
||||
```YAML
|
||||
name: default
|
||||
|
||||
kind: pipeline
|
||||
type: docker
|
||||
|
||||
steps:
|
||||
- name: backend
|
||||
image: golang
|
||||
commands:
|
||||
- go get
|
||||
- go build
|
||||
- go test
|
||||
|
||||
- name: frontend
|
||||
image: node:6
|
||||
commands:
|
||||
- npm install
|
||||
- npm test
|
||||
|
||||
- name: publish
|
||||
image: plugins/docker
|
||||
settings:
|
||||
repo: octocat/hello-world
|
||||
tags: [ 1, 1.1, latest ]
|
||||
registry: index.docker.io
|
||||
|
||||
- name: notify
|
||||
image: plugins/slack
|
||||
settings:
|
||||
channel: developers
|
||||
username: drone
|
||||
```
|
||||
|
||||
## Documentation and Other Links
|
||||
|
||||
* Setup Documentation [docs.drone.io/installation](http://docs.drone.io/installation/)
|
||||
* Usage Documentation [docs.drone.io/getting-started](http://docs.drone.io/getting-started/)
|
||||
* Plugin Index [plugins.drone.io](http://plugins.drone.io/)
|
||||
* Getting Help [discourse.drone.io](https://discourse.drone.io)
|
||||
* Build the Enterprise Edition [BUILDING](https://github.com/drone/drone/blob/master/BUILDING)
|
||||
* Build the Community Edition [BUILDING_OSS](https://github.com/drone/drone/blob/master/BUILDING_OSS)
|
||||
|
||||
## Building from source
|
||||
|
||||
We have two versions available: the [Enterprise Edition](https://github.com/drone/drone/blob/master/BUILDING) and the [Community Edition](https://github.com/drone/drone/blob/master/BUILDING_OSS)
|
||||
|
||||
## Release procedure
|
||||
|
||||
Run the changelog generator.
|
||||
|
||||
```BASH
|
||||
docker run -it --rm -v "$(pwd)":/usr/local/src/your-app githubchangeloggenerator/github-changelog-generator -u drone -p drone -t <secret github token>
|
||||
```
|
||||
|
||||
You can generate a token by logging into your GitHub account and going to Settings -> Personal access tokens.
|
||||
|
||||
Next we tag the PR's with the fixes or enhancements labels. If the PR does not fulfill the requirements, do not add a label.
|
||||
|
||||
**Before moving on make sure to update the version file `version/version.go && version/version_test.go`.**
|
||||
|
||||
Run the changelog generator again with the future version according to semver.
|
||||
|
||||
```BASH
|
||||
docker run -it --rm -v "$(pwd)":/usr/local/src/your-app githubchangeloggenerator/github-changelog-generator -u harness -p drone -t <secret token> --future-release v1.0.0
|
||||
```
|
||||
|
||||
Create your pull request for the release. Get it merged then tag the release.
|
||||
|
||||
[⬆ Back to Top](#table-of-contents)
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
# Security Policies and Procedures
|
||||
|
||||
This document outlines security procedures and general policies for this project.
|
||||
|
||||
* [Reporting a Bug](#reporting-a-bug)
|
||||
* [Disclosure Policy](#disclosure-policy)
|
||||
* [Comments on this Policy](#comments-on-this-policy)
|
||||
|
||||
## Reporting a Bug
|
||||
|
||||
Report security bugs by emailing the lead maintainer at security@drone.io.
|
||||
|
||||
The lead maintainer will acknowledge your email within 48 hours, and will send a
|
||||
more detailed response within 48 hours indicating the next steps in handling
|
||||
your report. After the initial reply to your report, the security team will
|
||||
endeavor to keep you informed of the progress towards a fix and full
|
||||
announcement, and may ask for additional information or guidance.
|
||||
|
||||
Report security bugs in third-party software to the person or team maintaining
|
||||
that software.
|
||||
|
||||
## Disclosure Policy
|
||||
|
||||
When the security team receives a security bug report, they will assign it to a
|
||||
primary handler. This person will coordinate the fix and release process,
|
||||
involving the following steps:
|
||||
|
||||
* Confirm the problem and determine the affected versions.
|
||||
* Audit code to find any potential similar problems.
|
||||
* Prepare fixes for all releases still under maintenance. These fixes will be
|
||||
released as fast as possible to DockerHub.
|
||||
|
||||
## Comments on this Policy
|
||||
|
||||
If you have suggestions on how this process could be improved please submit a
|
||||
pull request.
|
||||
|
|
@ -1,66 +0,0 @@
|
|||
name: CI Linter pipeline
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- v*
|
||||
branches:
|
||||
- master
|
||||
- main
|
||||
pull_request:
|
||||
permissions:
|
||||
contents: read
|
||||
# Optional: allow read access to pull request. Use with `only-new-issues` option.
|
||||
# pull-requests: read
|
||||
jobs:
|
||||
web:
|
||||
name: CI linter for js/ts
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 16
|
||||
cache: "npm"
|
||||
cache-dependency-path: web/yarn.lock
|
||||
- name: install, lint, and build web app
|
||||
working-directory: web
|
||||
run: |
|
||||
yarn install
|
||||
yarn check:all
|
||||
yarn build
|
||||
gitness:
|
||||
name: CI linter for go
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-go@v4
|
||||
with:
|
||||
go-version: '1.23'
|
||||
- name: get dependencies
|
||||
run: |
|
||||
mkdir -p ./web/dist
|
||||
touch ./web/dist/empty.txt
|
||||
- name: golangci-lint
|
||||
uses: golangci/golangci-lint-action@v3
|
||||
with:
|
||||
# Optional: version of golangci-lint to use in form of v1.2 or v1.2.3 or `latest` to use the latest version
|
||||
version: v1.64.5
|
||||
|
||||
# Optional: working directory, useful for monorepos
|
||||
# working-directory: somedir
|
||||
|
||||
# Optional: golangci-lint command line arguments.
|
||||
# args: --issues-exit-code=0
|
||||
|
||||
# Optional: show only new issues if it's a pull request. The default value is `false`.
|
||||
# only-new-issues: true
|
||||
|
||||
# Optional: if set to true then the all caching functionality will be complete disabled,
|
||||
# takes precedence over all other caching options.
|
||||
# skip-cache: true
|
||||
|
||||
# Optional: if set to true then the action don't cache or restore ~/go/pkg.
|
||||
# skip-pkg-cache: true
|
||||
|
||||
# Optional: if set to true then the action don't cache or restore ~/.cache/go-build.
|
||||
# skip-build-cache: true
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
since-tag=v2.0.4
|
||||
issues=false
|
||||
|
||||
|
|
@ -1,37 +1,13 @@
|
|||
.DS_Store
|
||||
NOTES*
|
||||
.vscode
|
||||
__debug_bin
|
||||
_research
|
||||
.env
|
||||
*.sqlite
|
||||
*.sqlite3
|
||||
web/node_modules
|
||||
web/dist
|
||||
web/coverage
|
||||
web/.yalc
|
||||
web/yalc.lock
|
||||
yarn-error*
|
||||
release
|
||||
*.txt
|
||||
*.out
|
||||
*.key
|
||||
.env
|
||||
.env.*
|
||||
release/
|
||||
scripts/*.go
|
||||
docker/**/data
|
||||
TODO*
|
||||
.idea
|
||||
.vscode/settings.json
|
||||
coverage.out
|
||||
gitness.session.sql
|
||||
web/cypress/node_modules
|
||||
*.rsa
|
||||
*.rsa.pub
|
||||
node_modules/
|
||||
dist
|
||||
.yalc
|
||||
yalc.lock
|
||||
node_modules
|
||||
.cursor
|
||||
|
||||
# ignore any executables we build
|
||||
/gitness
|
||||
/registry/logs/*
|
||||
/distribution-spec
|
||||
/registry/distribution-spec
|
||||
/app/store/database/test.db
|
||||
|
||||
# adding support for .http files
|
||||
http-client.private.env.json
|
||||
485
.golangci.yml
485
.golangci.yml
|
|
@ -1,485 +0,0 @@
|
|||
version: "2"
|
||||
linters:
|
||||
default: none
|
||||
enable:
|
||||
- asasalint
|
||||
- asciicheck
|
||||
- bidichk
|
||||
- bodyclose
|
||||
- contextcheck
|
||||
- copyloopvar
|
||||
- durationcheck
|
||||
- errcheck
|
||||
- errname
|
||||
- errorlint
|
||||
- exhaustive
|
||||
- forbidigo
|
||||
- goconst
|
||||
- gocritic
|
||||
- godot
|
||||
- goheader
|
||||
- gomoddirectives
|
||||
- gomodguard
|
||||
- goprintffuncname
|
||||
- gosec
|
||||
- govet
|
||||
- ineffassign
|
||||
- lll
|
||||
- makezero
|
||||
- misspell
|
||||
- nakedret
|
||||
- nestif
|
||||
- nilerr
|
||||
- nilnil
|
||||
- noctx
|
||||
- nosprintfhostport
|
||||
- predeclared
|
||||
- promlinter
|
||||
- reassign
|
||||
- revive
|
||||
- rowserrcheck
|
||||
- sqlclosecheck
|
||||
- staticcheck
|
||||
- tagliatelle
|
||||
- tparallel
|
||||
- unconvert
|
||||
- unparam
|
||||
- unused
|
||||
- usestdlibvars
|
||||
- wastedassign
|
||||
- whitespace
|
||||
settings:
|
||||
revive:
|
||||
rules:
|
||||
- name: var-naming
|
||||
severity: warning
|
||||
disabled: true
|
||||
errcheck:
|
||||
check-type-assertions: true
|
||||
gocritic:
|
||||
settings:
|
||||
captLocal:
|
||||
paramsOnly: false
|
||||
underef:
|
||||
skipRecvDeref: false
|
||||
goheader:
|
||||
template: |-
|
||||
Copyright 2023 Harness, Inc.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
gomodguard:
|
||||
blocked:
|
||||
modules:
|
||||
- github.com/golang/protobuf:
|
||||
recommendations:
|
||||
- google.golang.org/protobuf
|
||||
reason: see https://developers.google.com/protocol-buffers/docs/reference/go/faq#modules
|
||||
- github.com/satori/go.uuid:
|
||||
recommendations:
|
||||
- github.com/google/uuid
|
||||
reason: satori's package is not maintained
|
||||
- github.com/gofrs/uuid:
|
||||
recommendations:
|
||||
- github.com/google/uuid
|
||||
reason: 'see recommendation from dev-infra team: https://confluence.gtforge.com/x/gQI6Aw'
|
||||
govet:
|
||||
disable:
|
||||
- fieldalignment
|
||||
enable-all: true
|
||||
settings:
|
||||
shadow:
|
||||
strict: true
|
||||
nakedret:
|
||||
max-func-lines: 30
|
||||
rowserrcheck:
|
||||
packages:
|
||||
- github.com/jmoiron/sqlx
|
||||
staticcheck:
|
||||
checks:
|
||||
- all
|
||||
- -SA1019
|
||||
- -QF1008
|
||||
tagliatelle:
|
||||
case:
|
||||
rules:
|
||||
avro: snake
|
||||
bson: snake
|
||||
db: snake
|
||||
json: snake
|
||||
mapstructure: snake
|
||||
xml: snake
|
||||
yaml: snake
|
||||
exclusions:
|
||||
generated: lax
|
||||
presets:
|
||||
- comments
|
||||
- common-false-positives
|
||||
- legacy
|
||||
- std-error-handling
|
||||
rules:
|
||||
- linters:
|
||||
- govet
|
||||
text: 'shadow: declaration of "(err|ctx|ok)" shadows declaration at'
|
||||
- linters:
|
||||
- lll
|
||||
source: ^//\s*go:generate\s
|
||||
- linters:
|
||||
- gomoddirectives
|
||||
text: 'local replacement are not allowed: github.com/harness/gitness'
|
||||
- linters:
|
||||
- gomoddirectives
|
||||
text: 'replacement are not allowed: github.com/docker/docker'
|
||||
- linters:
|
||||
- godot
|
||||
source: (noinspection|TODO)
|
||||
- linters:
|
||||
- gocritic
|
||||
source: //noinspection
|
||||
- linters:
|
||||
- errorlint
|
||||
source: ^\s+if _, ok := err\.\([^.]+\.InternalError\); ok {
|
||||
- linters:
|
||||
- forbidigo
|
||||
path: ^cli/
|
||||
- linters:
|
||||
- revive
|
||||
- staticcheck
|
||||
- tagliatelle
|
||||
path: ^registry/app/manifest/.*
|
||||
- linters:
|
||||
- errorlint
|
||||
path: ^registry/app/dist_temp/.*
|
||||
- linters:
|
||||
- gocritic
|
||||
path: ^registry/app/driver/filesystem/.*
|
||||
- linters:
|
||||
- gocognit
|
||||
- gosec
|
||||
- nestif
|
||||
path: ^registry/app/driver/s3-aws/.*
|
||||
- linters:
|
||||
- goheader
|
||||
path: ^registry/app/remote/clients/registry/interceptor/interceptor.go
|
||||
- linters:
|
||||
- goheader
|
||||
path: ^registry/app/common/http/modifier/modifier.go
|
||||
- linters:
|
||||
- goheader
|
||||
path: ^registry/app/driver/fileinfo.go
|
||||
- linters:
|
||||
- goheader
|
||||
path: ^registry/app/driver/storagedriver.go
|
||||
- linters:
|
||||
- goheader
|
||||
path: ^registry/app/driver/walk.go
|
||||
- linters:
|
||||
- goheader
|
||||
path: ^registry/app/dist_temp/challenge/addr.go
|
||||
- linters:
|
||||
- goheader
|
||||
path: ^registry/app/dist_temp/challenge/authchallenge.go
|
||||
- linters:
|
||||
- goheader
|
||||
path: ^registry/app/dist_temp/challenge/authchallenge_test.go
|
||||
- linters:
|
||||
- goheader
|
||||
path: ^registry/app/dist_temp/requestutil/util.go
|
||||
- linters:
|
||||
- goheader
|
||||
path: ^registry/app/dist_temp/requestutil/util_test.go
|
||||
- linters:
|
||||
- goheader
|
||||
path: ^registry/app/pkg/commons/zipreader/*
|
||||
- linters:
|
||||
- goheader
|
||||
path: ^registry/app/manifest/descriptor.go
|
||||
- linters:
|
||||
- goheader
|
||||
path: ^registry/app/manifest/doc.go
|
||||
- linters:
|
||||
- goheader
|
||||
path: ^registry/app/manifest/errors.go
|
||||
- linters:
|
||||
- goheader
|
||||
path: ^registry/app/manifest/manifests.go
|
||||
- linters:
|
||||
- goheader
|
||||
path: ^registry/app/manifest/versioned.go
|
||||
- linters:
|
||||
- goheader
|
||||
path: ^registry/app/common/lib/authorizer.go
|
||||
- linters:
|
||||
- goheader
|
||||
path: ^registry/app/common/lib/link.go
|
||||
- linters:
|
||||
- goheader
|
||||
path: ^registry/app/common/http/tls.go
|
||||
- linters:
|
||||
- goheader
|
||||
path: ^registry/app/common/http/transport.go
|
||||
- linters:
|
||||
- goheader
|
||||
path: ^registry/app/common/http/transport_test.go
|
||||
- linters:
|
||||
- goheader
|
||||
path: ^registry/app/manifest/schema2/manifest.go
|
||||
- linters:
|
||||
- goheader
|
||||
path: ^registry/app/manifest/schema2/manifest_test.go
|
||||
- linters:
|
||||
- goheader
|
||||
path: ^registry/app/manifest/ocischema/index.go
|
||||
- linters:
|
||||
- goheader
|
||||
path: ^registry/app/manifest/ocischema/manifest.go
|
||||
- linters:
|
||||
- goheader
|
||||
path: ^registry/app/remote/clients/registry/auth/null/authorizer.go
|
||||
- linters:
|
||||
- goheader
|
||||
path: ^registry/app/remote/clients/registry/auth/basic/authorizer.go
|
||||
- linters:
|
||||
- goheader
|
||||
path: ^registry/app/remote/clients/registry/auth/basic/authorizer_test.go
|
||||
- linters:
|
||||
- goheader
|
||||
path: ^registry/app/common/lib/errors/const.go
|
||||
- linters:
|
||||
- goheader
|
||||
path: ^registry/app/common/lib/errors/errors.go
|
||||
- linters:
|
||||
- goheader
|
||||
path: ^registry/app/common/lib/errors/stack.go
|
||||
- linters:
|
||||
- goheader
|
||||
path: ^registry/app/common/lib/errors/stack_test.go
|
||||
- linters:
|
||||
- goheader
|
||||
path: ^registry/app/remote/clients/registry/auth/bearer/authorizer.go
|
||||
- linters:
|
||||
- goheader
|
||||
path: ^registry/app/remote/clients/registry/auth/bearer/cache.go
|
||||
- linters:
|
||||
- goheader
|
||||
path: ^registry/app/remote/clients/registry/auth/bearer/scope.go
|
||||
- linters:
|
||||
- goheader
|
||||
path: ^registry/app/manifest/manifestlist/manifestlist.go
|
||||
- linters:
|
||||
- goheader
|
||||
path: ^registry/app/manifest/manifestlist/manifestlist_test.go
|
||||
- linters:
|
||||
- goheader
|
||||
path: ^registry/app/driver/factory/factory.go
|
||||
- linters:
|
||||
- goheader
|
||||
path: ^registry/app/dist_temp/dcontext/context.go
|
||||
- linters:
|
||||
- goheader
|
||||
path: ^registry/app/dist_temp/dcontext/doc.go
|
||||
- linters:
|
||||
- goheader
|
||||
path: ^registry/app/dist_temp/dcontext/http.go
|
||||
- linters:
|
||||
- goheader
|
||||
path: ^registry/app/dist_temp/dcontext/logger.go
|
||||
- linters:
|
||||
- goheader
|
||||
path: ^registry/app/dist_temp/dcontext/trace.go
|
||||
- linters:
|
||||
- goheader
|
||||
path: ^registry/app/dist_temp/dcontext/util.go
|
||||
- linters:
|
||||
- goheader
|
||||
path: ^registry/app/dist_temp/dcontext/version.go
|
||||
- linters:
|
||||
- goheader
|
||||
path: ^registry/app/dist_temp/dcontext/http_test.go
|
||||
- linters:
|
||||
- goheader
|
||||
path: ^registry/app/dist_temp/dcontext/trace_test.go
|
||||
- linters:
|
||||
- goheader
|
||||
path: ^registry/app/dist_temp/dcontext/version_test.go
|
||||
- linters:
|
||||
- goheader
|
||||
path: ^registry/app/driver/base/base.go
|
||||
- linters:
|
||||
- goheader
|
||||
path: ^registry/app/driver/base/regulator.go
|
||||
- linters:
|
||||
- goheader
|
||||
path: ^registry/app/driver/base/regulator_test.go
|
||||
- linters:
|
||||
- goheader
|
||||
path: ^registry/app/storage/blobs.go
|
||||
- linters:
|
||||
- goheader
|
||||
path: ^registry/app/storage/blobwriter.go
|
||||
- linters:
|
||||
- goheader
|
||||
path: ^registry/app/storage/blobwriter_resumable.go
|
||||
- linters:
|
||||
- goheader
|
||||
path: ^registry/app/storage/errors.go
|
||||
- linters:
|
||||
- goheader
|
||||
path: ^registry/app/storage/filereader.go
|
||||
- linters:
|
||||
- goheader
|
||||
path: ^registry/app/storage/gcstoragelient.go
|
||||
- linters:
|
||||
- goheader
|
||||
path: ^registry/app/storage/io.go
|
||||
- linters:
|
||||
- goheader
|
||||
path: ^registry/app/storage/middleware.go
|
||||
- linters:
|
||||
- goheader
|
||||
path: ^registry/app/storage/ociblobstore.go
|
||||
- linters:
|
||||
- goheader
|
||||
path: ^registry/app/storage/paths.go
|
||||
- linters:
|
||||
- goheader
|
||||
path: ^registry/app/storage/storageservice.go
|
||||
- linters:
|
||||
- goheader
|
||||
path: ^registry/app/remote/clients/registry/client.go
|
||||
- linters:
|
||||
- goheader
|
||||
path: ^registry/app/remote/adapter/adapter.go
|
||||
- linters:
|
||||
- goheader
|
||||
path: ^registry/app/remote/clients/registry/auth/authorizer.go
|
||||
- linters:
|
||||
- goheader
|
||||
path: ^registry/app/driver/s3-aws/s3.go
|
||||
- linters:
|
||||
- goheader
|
||||
path: ^registry/app/driver/s3-aws/s3_v2_signer.go
|
||||
- linters:
|
||||
- goheader
|
||||
path: ^registry/app/driver/filesystem/driver.go
|
||||
- linters:
|
||||
- goheader
|
||||
path: ^registry/app/pkg/docker/app.go
|
||||
- linters:
|
||||
- goheader
|
||||
path: ^registry/app/pkg/docker/catalog.go
|
||||
- linters:
|
||||
- goheader
|
||||
path: ^registry/app/pkg/docker/compat.go
|
||||
- linters:
|
||||
- goheader
|
||||
path: ^registry/app/pkg/docker/context.go
|
||||
- linters:
|
||||
- goheader
|
||||
path: ^registry/app/pkg/docker/controller.go
|
||||
- linters:
|
||||
- goheader
|
||||
path: ^registry/app/pkg/docker/local.go
|
||||
- linters:
|
||||
- goheader
|
||||
path: ^registry/app/pkg/docker/manifest_service.go
|
||||
- linters:
|
||||
- goheader
|
||||
path: ^registry/app/pkg/docker/remote.go
|
||||
- linters:
|
||||
- goheader
|
||||
path: ^registry/app/remote/adapter/dockerhub/adapter.go
|
||||
- linters:
|
||||
- goheader
|
||||
path: ^registry/app/remote/adapter/awsecr/adapter.go
|
||||
- linters:
|
||||
- goheader
|
||||
path: ^registry/app/remote/adapter/maven/adapter.go
|
||||
- linters:
|
||||
- goheader
|
||||
path: ^registry/app/remote/adapter/awsecr/auth.go
|
||||
- linters:
|
||||
- goheader
|
||||
path: ^registry/app/remote/adapter/dockerhub/client.go
|
||||
- linters:
|
||||
- goheader
|
||||
path: ^registry/app/remote/adapter/dockerhub/consts.go
|
||||
- linters:
|
||||
- goheader
|
||||
path: ^registry/app/driver/testsuites/testsuites.go
|
||||
- linters:
|
||||
- goheader
|
||||
path: ^registry/app/dist_temp/errcode/errors.go
|
||||
- linters:
|
||||
- goheader
|
||||
path: ^registry/app/dist_temp/errcode/handler.go
|
||||
- linters:
|
||||
- goheader
|
||||
path: ^registry/app/dist_temp/errcode/register.go
|
||||
- linters:
|
||||
- goheader
|
||||
path: ^registry/app/remote/controller/proxy/controller.go
|
||||
- linters:
|
||||
- goheader
|
||||
path: ^registry/app/remote/controller/proxy/inflight.go
|
||||
- linters:
|
||||
- goheader
|
||||
path: ^registry/app/remote/controller/proxy/local.go
|
||||
- linters:
|
||||
- goheader
|
||||
path: ^registry/app/remote/controller/proxy/remote.go
|
||||
- linters:
|
||||
- goheader
|
||||
path: ^registry/app/remote/controller/proxy/inflight_test.go
|
||||
- linters:
|
||||
- goheader
|
||||
path: ^registry/app/remote/adapter/native/adapter.go
|
||||
- linters:
|
||||
- gosec
|
||||
path: ^registry/app/storage/blobStore.go
|
||||
- linters:
|
||||
- lll
|
||||
- tagliatelle
|
||||
path: ^registry/app/metadata/nuget/metadata.go
|
||||
- linters:
|
||||
- errcheck
|
||||
- gocritic
|
||||
- godot
|
||||
- goheader
|
||||
- lll
|
||||
path: ^registry/app/api/controller/mocks/
|
||||
paths:
|
||||
- third_party$
|
||||
- builtin$
|
||||
- examples$
|
||||
|
||||
issues:
|
||||
max-same-issues: 10
|
||||
formatters:
|
||||
enable:
|
||||
- gci
|
||||
- goimports
|
||||
settings:
|
||||
gci:
|
||||
sections:
|
||||
- standard
|
||||
- prefix(github.com/harness/gitness)
|
||||
- default
|
||||
- blank
|
||||
- dot
|
||||
custom-order: true
|
||||
exclusions:
|
||||
generated: lax
|
||||
paths:
|
||||
- third_party$
|
||||
- builtin$
|
||||
- examples$
|
||||
19
.local.env
19
.local.env
|
|
@ -1,19 +0,0 @@
|
|||
GITNESS_TRACE=true
|
||||
GITNESS_GIT_TRACE=true
|
||||
GITNESS_PRINCIPAL_ADMIN_EMAIL=admin@gitness.io
|
||||
GITNESS_PRINCIPAL_ADMIN_PASSWORD=changeit
|
||||
GITNESS_WEBHOOK_ALLOW_LOOPBACK=true
|
||||
GITNESS_METRIC_ENABLED=false
|
||||
GITNESS_HTTP_HOST=localhost
|
||||
GITNESS_GITSPACE_ENABLE=true
|
||||
GITNESS_DEBUG=true
|
||||
GITNESS_DOCKER_API_VERSION=1.45
|
||||
GITNESS_SSH_ENABLE=true
|
||||
GITNESS_SSH_HOST=localhost
|
||||
GITNESS_SSH_PORT=2222
|
||||
|
||||
GITNESS_REGISTRY_STORAGE_TYPE=filesystem
|
||||
GITNESS_REGISTRY_FILESYSTEM_ROOT_DIRECTORY=/tmp
|
||||
|
||||
#GITNESS_DATABASE_DRIVER=postgres
|
||||
#GITNESS_DATABASE_DATASOURCE=postgres://postgres:postgres@localhost:5432/gitness?sslmode=disable
|
||||
|
|
@ -1,28 +0,0 @@
|
|||
GET {{baseurl}}/repos/root/{{repo}}/+/diff/{{targetBranch}}...{{sourceBranch}}
|
||||
Accept: text/plain
|
||||
Authorization: {{token}}
|
||||
|
||||
### Get diff ignore white space
|
||||
GET {{baseurl}}/repos/root/{{repo}}/+/diff/{{targetBranch}}...{{sourceBranch}}?ignore_whitespace=true
|
||||
Accept: text/plain
|
||||
Authorization: {{token}}
|
||||
|
||||
### Get diff with hidden white spaces
|
||||
GET {{baseurl}}/repos/root/{{repo}}/+/commits/{{commit}}/diff
|
||||
Accept: text/plain
|
||||
Authorization: {{token}}
|
||||
|
||||
### Get commit diff ignore white space
|
||||
GET {{baseurl}}/repos/root/{{repo}}/+/commits/{{commit}}/diff?ignore_whitespace=true
|
||||
Accept: text/plain
|
||||
Authorization: {{token}}
|
||||
|
||||
### Get diff stats
|
||||
GET {{baseurl}}/repos/root/{{repo}}/+/diff-stats/{{targetBranch}}...{{sourceBranch}}
|
||||
Accept: text/plain
|
||||
Authorization: {{token}}
|
||||
|
||||
### Get diff stats ignore white space
|
||||
GET {{baseurl}}/repos/root/{{repo}}/+/diff-stats/{{targetBranch}}...{{sourceBranch}}?ignore_whitespace=true
|
||||
Accept: text/plain
|
||||
Authorization: {{token}}
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
{
|
||||
"dev": {
|
||||
"baseurl": "http://localhost:3000/api/v1"
|
||||
}
|
||||
}
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
POST {{baseurl}}/login
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"login_identifier": "{{login_identifier}}",
|
||||
"password": "{{password}}"
|
||||
}
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
### Get metric for space
|
||||
|
||||
GET {{baseurl}}/spaces/root/+/usage/metric
|
||||
Authorization: {{token}}
|
||||
|
|
@ -1,18 +0,0 @@
|
|||
{
|
||||
// Use IntelliSense to learn about possible attributes.
|
||||
// Hover to view descriptions of existing attributes.
|
||||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
//TODO update this when we are ready to cutover
|
||||
"name": "Gitness",
|
||||
"type": "go",
|
||||
"request": "launch",
|
||||
"mode": "auto",
|
||||
"buildFlags": "",
|
||||
"program": "cmd/gitness",
|
||||
"args": ["server", "../../.local.env"]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
1. Clone the repository
|
||||
2. Install go 1.11 or later with Go modules enabled
|
||||
3. Install binaries to $GOPATH/bin
|
||||
|
||||
go install github.com/drone/drone/cmd/drone-server
|
||||
|
||||
4. Start the server at localhost:8080
|
||||
|
||||
export DRONE_GITHUB_CLIENT_ID=...
|
||||
export DRONE_GITHUB_CLIENT_SECRET=...
|
||||
drone-server
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
1. Clone the repository
|
||||
2. Install go 1.11 or later with Go modules enabled
|
||||
3. Install binaries to $GOPATH/bin
|
||||
|
||||
go install -tags "oss nolimit" github.com/drone/drone/cmd/drone-server
|
||||
|
||||
4. Start the server at localhost:8080
|
||||
|
||||
export DRONE_GITHUB_CLIENT_ID=...
|
||||
export DRONE_GITHUB_CLIENT_SECRET=...
|
||||
drone-server
|
||||
|
|
@ -0,0 +1,797 @@
|
|||
# Changelog
|
||||
|
||||
## [v2.20.0](https://github.com/harness/drone/tree/v2.20.0) (2023-08-21)
|
||||
|
||||
[Full Changelog](https://github.com/harness/drone/compare/v2.19.0...v2.20.0)
|
||||
|
||||
**Implemented enhancements:**
|
||||
|
||||
- + sync gitea redirecturl config from gitee for customize login redire… [\#3319](https://github.com/harness/drone/pull/3319) ([fireinice](https://github.com/fireinice))
|
||||
|
||||
**Fixed bugs:**
|
||||
|
||||
- \(CI-8780\) set approved stages to waiting, if they have stage depende… [\#3355](https://github.com/harness/drone/pull/3355) ([tphoney](https://github.com/tphoney))
|
||||
|
||||
## [v2.19.0](https://github.com/harness/drone/tree/v2.19.0) (2023-08-15)
|
||||
|
||||
[Full Changelog](https://github.com/harness/drone/compare/scheduler_experiment...v2.19.0)
|
||||
|
||||
**Implemented enhancements:**
|
||||
|
||||
- Support arbitrary action value from parameter in query string [\#3341](https://github.com/harness/drone/pull/3341) ([filippopisano](https://github.com/filippopisano))
|
||||
|
||||
**Fixed bugs:**
|
||||
|
||||
- bump drone-ui to 2.11.5 [\#3350](https://github.com/harness/drone/pull/3350) ([d1wilko](https://github.com/d1wilko))
|
||||
- bump drone-ui to 2.11.4 [\#3349](https://github.com/harness/drone/pull/3349) ([d1wilko](https://github.com/d1wilko))
|
||||
- \(fix\) prevent scheduler deadlock [\#3344](https://github.com/harness/drone/pull/3344) ([tphoney](https://github.com/tphoney))
|
||||
- bump drone-ui to 2.11.3 [\#3337](https://github.com/harness/drone/pull/3337) ([d1wilko](https://github.com/d1wilko))
|
||||
|
||||
**Merged pull requests:**
|
||||
|
||||
- \(maint\) prep for v2.19.0 [\#3352](https://github.com/harness/drone/pull/3352) ([tphoney](https://github.com/tphoney))
|
||||
- remove repetitive words [\#3342](https://github.com/harness/drone/pull/3342) ([cuishuang](https://github.com/cuishuang))
|
||||
- Revert "fix scheduler queue deadlock" [\#3331](https://github.com/harness/drone/pull/3331) ([tphoney](https://github.com/tphoney))
|
||||
|
||||
## [scheduler_experiment](https://github.com/harness/drone/tree/scheduler_experiment) (2023-07-05)
|
||||
|
||||
[Full Changelog](https://github.com/harness/drone/compare/v2.18.0...scheduler_experiment)
|
||||
|
||||
**Fixed bugs:**
|
||||
|
||||
- fix scheduler queue deadlock [\#3330](https://github.com/harness/drone/pull/3330) ([tphoney](https://github.com/tphoney))
|
||||
|
||||
## [v2.18.0](https://github.com/harness/drone/tree/v2.18.0) (2023-07-04)
|
||||
|
||||
[Full Changelog](https://github.com/harness/drone/compare/v2.17.0...v2.18.0)
|
||||
|
||||
**Implemented enhancements:**
|
||||
|
||||
- support custom pipeline message [\#3294](https://github.com/harness/drone/pull/3294) ([zc2638](https://github.com/zc2638))
|
||||
|
||||
**Fixed bugs:**
|
||||
|
||||
- bump drone-ui to 2.11.2 [\#3327](https://github.com/harness/drone/pull/3327) ([d1wilko](https://github.com/d1wilko))
|
||||
- Fix comment errors [\#3302](https://github.com/harness/drone/pull/3302) ([weidongkl](https://github.com/weidongkl))
|
||||
|
||||
**Merged pull requests:**
|
||||
|
||||
- v2.18.0 release prep [\#3328](https://github.com/harness/drone/pull/3328) ([tphoney](https://github.com/tphoney))
|
||||
|
||||
## [v2.17.0](https://github.com/harness/drone/tree/v2.17.0) (2023-04-25)
|
||||
|
||||
[Full Changelog](https://github.com/harness/drone/compare/v2.16.0...v2.17.0)
|
||||
|
||||
**Implemented enhancements:**
|
||||
|
||||
- Add `authtype` to logging middleware [\#3310](https://github.com/harness/drone/pull/3310) ([colinhoglund](https://github.com/colinhoglund))
|
||||
- Add config for the buffer [\#3308](https://github.com/harness/drone/pull/3308) ([TheJokersThief](https://github.com/TheJokersThief))
|
||||
|
||||
**Fixed bugs:**
|
||||
|
||||
- store/card: fix dropped error [\#3300](https://github.com/harness/drone/pull/3300) ([alrs](https://github.com/alrs))
|
||||
- bump drone-ui to 2.9.1 [\#3298](https://github.com/harness/drone/pull/3298) ([d1wilko](https://github.com/d1wilko))
|
||||
- Starlark: Update `go.starlark.net` dependency [\#3284](https://github.com/harness/drone/pull/3284) ([dsotirakis](https://github.com/dsotirakis))
|
||||
|
||||
**Merged pull requests:**
|
||||
|
||||
- release prep for v2.17.0 [\#3316](https://github.com/harness/drone/pull/3316) ([eoinmcafee00](https://github.com/eoinmcafee00))
|
||||
- bump drone-ui to 2.11.1 [\#3315](https://github.com/harness/drone/pull/3315) ([d1wilko](https://github.com/d1wilko))
|
||||
- bump drone-ui to 2.11.0 [\#3313](https://github.com/harness/drone/pull/3313) ([d1wilko](https://github.com/d1wilko))
|
||||
- bump drone-ui to 2.10.0 [\#3311](https://github.com/harness/drone/pull/3311) ([d1wilko](https://github.com/d1wilko))
|
||||
- \(maint\) move to use the arm64 pool [\#3296](https://github.com/harness/drone/pull/3296) ([tphoney](https://github.com/tphoney))
|
||||
|
||||
## [v2.16.0](https://github.com/harness/drone/tree/v2.16.0) (2022-12-15)
|
||||
|
||||
[Full Changelog](https://github.com/harness/drone/compare/v2.15.0...v2.16.0)
|
||||
|
||||
**Implemented enhancements:**
|
||||
|
||||
- Make Starlark file size limit configurable [\#3291](https://github.com/harness/drone/pull/3291) ([andrii-kasparevych](https://github.com/andrii-kasparevych))
|
||||
- Enhance status check label for promotions [\#3263](https://github.com/harness/drone/pull/3263) ([michelangelomo](https://github.com/michelangelomo))
|
||||
|
||||
**Fixed bugs:**
|
||||
|
||||
- \(bugfix\) bump go-scm to v1.28.0 [\#3290](https://github.com/harness/drone/pull/3290) ([tphoney](https://github.com/tphoney))
|
||||
|
||||
**Merged pull requests:**
|
||||
|
||||
- \(maint\) 2.16.0 release prep [\#3295](https://github.com/harness/drone/pull/3295) ([tphoney](https://github.com/tphoney))
|
||||
|
||||
## [v2.15.0](https://github.com/harness/drone/tree/v2.15.0) (2022-10-28)
|
||||
|
||||
[Full Changelog](https://github.com/harness/drone/compare/v2.14.0...v2.15.0)
|
||||
|
||||
**Implemented enhancements:**
|
||||
|
||||
- bump ui version [\#3279](https://github.com/harness/drone/pull/3279) ([d1wilko](https://github.com/d1wilko))
|
||||
- Add endpoint for allowing admins to force rotate a user's token [\#3272](https://github.com/harness/drone/pull/3272) ([ShiftedMr](https://github.com/ShiftedMr))
|
||||
|
||||
**Merged pull requests:**
|
||||
|
||||
- release prep v2.15.0 [\#3281](https://github.com/harness/drone/pull/3281) ([d1wilko](https://github.com/d1wilko))
|
||||
|
||||
## [v2.14.0](https://github.com/harness/drone/tree/v2.14.0) (2022-10-18)
|
||||
|
||||
[Full Changelog](https://github.com/harness/drone/compare/v2.13.0...v2.14.0)
|
||||
|
||||
**Implemented enhancements:**
|
||||
|
||||
- \(DRON-418\) send webhook and set status for failed builds [\#3266](https://github.com/harness/drone/pull/3266) ([tphoney](https://github.com/tphoney))
|
||||
|
||||
**Merged pull requests:**
|
||||
|
||||
- v2.14.0 release prep [\#3275](https://github.com/harness/drone/pull/3275) ([d1wilko](https://github.com/d1wilko))
|
||||
|
||||
## [v2.13.0](https://github.com/harness/drone/tree/v2.13.0) (2022-09-21)
|
||||
|
||||
[Full Changelog](https://github.com/harness/drone/compare/v2.12.1...v2.13.0)
|
||||
|
||||
**Implemented enhancements:**
|
||||
|
||||
- feat: update drone-yaml module [\#3249](https://github.com/harness/drone/pull/3249) ([jimsheldon](https://github.com/jimsheldon))
|
||||
- support time zone [\#3241](https://github.com/harness/drone/pull/3241) ([zc2638](https://github.com/zc2638))
|
||||
|
||||
**Fixed bugs:**
|
||||
|
||||
- update discourse.drone.io to community.harness.io [\#3261](https://github.com/harness/drone/pull/3261) ([kit101](https://github.com/kit101))
|
||||
- \(DRON-392\) cascade deletes on purge [\#3243](https://github.com/harness/drone/pull/3243) ([tphoney](https://github.com/tphoney))
|
||||
- Template converter, don't skip .yaml extension. [\#3242](https://github.com/harness/drone/pull/3242) ([staffanselander](https://github.com/staffanselander))
|
||||
|
||||
**Merged pull requests:**
|
||||
|
||||
- v2.13.0 release prep [\#3268](https://github.com/harness/drone/pull/3268) ([tphoney](https://github.com/tphoney))
|
||||
- \(maint\) disable arm builds [\#3262](https://github.com/harness/drone/pull/3262) ([tphoney](https://github.com/tphoney))
|
||||
- Update links to discourse in issue template [\#3233](https://github.com/harness/drone/pull/3233) ([alikhil](https://github.com/alikhil))
|
||||
|
||||
## [v2.12.1](https://github.com/harness/drone/tree/v2.12.1) (2022-06-15)
|
||||
|
||||
[Full Changelog](https://github.com/harness/drone/compare/v2.12.0...v2.12.1)
|
||||
|
||||
**Fixed bugs:**
|
||||
|
||||
- \(bug\) - fix original template scripts & remove amend scripts [\#3229](https://github.com/harness/drone/pull/3229) ([eoinmcafee00](https://github.com/eoinmcafee00))
|
||||
- \(bug\) - remove unique index on template name [\#3226](https://github.com/harness/drone/pull/3226) ([eoinmcafee00](https://github.com/eoinmcafee00))
|
||||
- Added OAuth2 token refresher for Gitlab [\#3215](https://github.com/harness/drone/pull/3215) ([EndymionWight](https://github.com/EndymionWight))
|
||||
|
||||
**Merged pull requests:**
|
||||
|
||||
- release prep for v2.12.1 [\#3232](https://github.com/harness/drone/pull/3232) ([eoinmcafee00](https://github.com/eoinmcafee00))
|
||||
- \(maint\) fix starlark test on windows [\#3230](https://github.com/harness/drone/pull/3230) ([tphoney](https://github.com/tphoney))
|
||||
- \(maint\) fix unit tests so they pass on windows [\#3228](https://github.com/harness/drone/pull/3228) ([tphoney](https://github.com/tphoney))
|
||||
- Update Readme to Fix Typo [\#3223](https://github.com/harness/drone/pull/3223) ([hrittikhere](https://github.com/hrittikhere))
|
||||
- \(bug\) add unit test for comments in template file [\#3221](https://github.com/harness/drone/pull/3221) ([eoinmcafee00](https://github.com/eoinmcafee00))
|
||||
- Bump scm version to v1.24.0 [\#3219](https://github.com/harness/drone/pull/3219) ([kit101](https://github.com/kit101))
|
||||
|
||||
## [v2.12.0](https://github.com/harness/drone/tree/v2.12.0) (2022-05-16)
|
||||
|
||||
[Full Changelog](https://github.com/harness/drone/compare/v2.11.1...v2.12.0)
|
||||
|
||||
**Implemented enhancements:**
|
||||
|
||||
- bump SCM version to v1.21.1 [\#3204](https://github.com/harness/drone/pull/3204) ([d1wilko](https://github.com/d1wilko))
|
||||
- bump ui version [\#3202](https://github.com/harness/drone/pull/3202) ([d1wilko](https://github.com/d1wilko))
|
||||
|
||||
**Fixed bugs:**
|
||||
|
||||
- \(fix\) update drone ui to 2.8.2 [\#3211](https://github.com/harness/drone/pull/3211) ([tphoney](https://github.com/tphoney))
|
||||
- \(dron-267\) correctly set parent for promotion retry [\#3210](https://github.com/harness/drone/pull/3210) ([tphoney](https://github.com/tphoney))
|
||||
|
||||
**Merged pull requests:**
|
||||
|
||||
- release prep v2.12.0 [\#3214](https://github.com/harness/drone/pull/3214) ([tphoney](https://github.com/tphoney))
|
||||
- fixing URL [\#3208](https://github.com/harness/drone/pull/3208) ([dnielsen](https://github.com/dnielsen))
|
||||
- update community information with updated links [\#3199](https://github.com/harness/drone/pull/3199) ([mrsantons](https://github.com/mrsantons))
|
||||
|
||||
## [v2.11.1](https://github.com/harness/drone/tree/v2.11.1) (2022-03-15)
|
||||
|
||||
[Full Changelog](https://github.com/harness/drone/compare/v2.11.0...v2.11.1)
|
||||
|
||||
**Fixed bugs:**
|
||||
|
||||
- ignore nil repos in list and add better debugging [\#3196](https://github.com/harness/drone/pull/3196) ([d1wilko](https://github.com/d1wilko))
|
||||
|
||||
**Merged pull requests:**
|
||||
|
||||
- \(maint\) release prep for 2.11.1 [\#3197](https://github.com/harness/drone/pull/3197) ([d1wilko](https://github.com/d1wilko))
|
||||
|
||||
## [v2.11.0](https://github.com/harness/drone/tree/v2.11.0) (2022-03-08)
|
||||
|
||||
[Full Changelog](https://github.com/harness/drone/compare/v2.10.0...v2.11.0)
|
||||
|
||||
**Implemented enhancements:**
|
||||
|
||||
- bump UI and SCM versions [\#3193](https://github.com/harness/drone/pull/3193) ([d1wilko](https://github.com/d1wilko))
|
||||
|
||||
**Merged pull requests:**
|
||||
|
||||
- \(maint\) release prep for 2.11.0 [\#3194](https://github.com/harness/drone/pull/3194) ([d1wilko](https://github.com/d1wilko))
|
||||
|
||||
## [v2.10.0](https://github.com/harness/drone/tree/v2.10.0) (2022-03-03)
|
||||
|
||||
[Full Changelog](https://github.com/harness/drone/compare/v2.9.1...v2.10.0)
|
||||
|
||||
**Implemented enhancements:**
|
||||
|
||||
- bump UI version to v2.7.0 [\#3190](https://github.com/harness/drone/pull/3190) ([d1wilko](https://github.com/d1wilko))
|
||||
- bump UI version to v2.6.2 [\#3188](https://github.com/harness/drone/pull/3188) ([d1wilko](https://github.com/d1wilko))
|
||||
|
||||
**Merged pull requests:**
|
||||
|
||||
- \(maint\) release prep for 2.10.0 [\#3191](https://github.com/harness/drone/pull/3191) ([d1wilko](https://github.com/d1wilko))
|
||||
|
||||
## [v2.9.1](https://github.com/harness/drone/tree/v2.9.1) (2022-01-27)
|
||||
|
||||
[Full Changelog](https://github.com/harness/drone/compare/v2.9.0...v2.9.1)
|
||||
|
||||
**Fixed bugs:**
|
||||
|
||||
- bump ui version 2.6.1 [\#3185](https://github.com/harness/drone/pull/3185) ([d1wilko](https://github.com/d1wilko))
|
||||
|
||||
**Merged pull requests:**
|
||||
|
||||
- \(maint\) release prep for 2.9.1 [\#3186](https://github.com/harness/drone/pull/3186) ([tphoney](https://github.com/tphoney))
|
||||
|
||||
## [v2.9.0](https://github.com/harness/drone/tree/v2.9.0) (2022-01-26)
|
||||
|
||||
[Full Changelog](https://github.com/harness/drone/compare/v2.8.0...v2.9.0)
|
||||
|
||||
**Implemented enhancements:**
|
||||
|
||||
- bump ui to v2.6.0 [\#3183](https://github.com/harness/drone/pull/3183) ([eoinmcafee00](https://github.com/eoinmcafee00))
|
||||
|
||||
**Merged pull requests:**
|
||||
|
||||
- release prep for v2.9.0 [\#3184](https://github.com/harness/drone/pull/3184) ([eoinmcafee00](https://github.com/eoinmcafee00))
|
||||
|
||||
## [v2.8.0](https://github.com/harness/drone/tree/v2.8.0) (2022-01-11)
|
||||
|
||||
[Full Changelog](https://github.com/harness/drone/compare/v2.7.3...v2.8.0)
|
||||
|
||||
**Implemented enhancements:**
|
||||
|
||||
- bump UI to v2.5.0 [\#3180](https://github.com/harness/drone/pull/3180) ([eoinmcafee00](https://github.com/eoinmcafee00))
|
||||
- \(feat\) ignore archive repos on sync [\#3178](https://github.com/harness/drone/pull/3178) ([eoinmcafee00](https://github.com/eoinmcafee00))
|
||||
- Datadog add the tag of 'remote:gitee' [\#3174](https://github.com/harness/drone/pull/3174) ([kit101](https://github.com/kit101))
|
||||
- Add tag filter when call build list endpoint [\#3173](https://github.com/harness/drone/pull/3173) ([michelangelomo](https://github.com/michelangelomo))
|
||||
|
||||
**Fixed bugs:**
|
||||
|
||||
- \(maint\) add warning around typo for stage\_id in step struct [\#3179](https://github.com/harness/drone/pull/3179) ([tphoney](https://github.com/tphoney))
|
||||
|
||||
**Merged pull requests:**
|
||||
|
||||
- release prep v2.8.0 [\#3181](https://github.com/harness/drone/pull/3181) ([eoinmcafee00](https://github.com/eoinmcafee00))
|
||||
|
||||
## [v2.7.3](https://github.com/harness/drone/tree/v2.7.3) (2021-12-30)
|
||||
|
||||
[Full Changelog](https://github.com/harness/drone/compare/v2.7.2...v2.7.3)
|
||||
|
||||
**Fixed bugs:**
|
||||
|
||||
- bump go-scm to v1.16.3 [\#3175](https://github.com/harness/drone/pull/3175) ([eoinmcafee00](https://github.com/eoinmcafee00))
|
||||
|
||||
**Merged pull requests:**
|
||||
|
||||
- release prep v2.7.3 [\#3176](https://github.com/harness/drone/pull/3176) ([eoinmcafee00](https://github.com/eoinmcafee00))
|
||||
|
||||
## [v2.7.2](https://github.com/harness/drone/tree/v2.7.2) (2021-12-19)
|
||||
|
||||
[Full Changelog](https://github.com/harness/drone/compare/v2.7.1...v2.7.2)
|
||||
|
||||
**Implemented enhancements:**
|
||||
|
||||
- bump go-scm to v1.16.2 [\#3169](https://github.com/harness/drone/pull/3169) ([kit101](https://github.com/kit101))
|
||||
|
||||
**Fixed bugs:**
|
||||
|
||||
- fixbug gitee provide refresher [\#3168](https://github.com/harness/drone/pull/3168) ([kit101](https://github.com/kit101))
|
||||
|
||||
**Merged pull requests:**
|
||||
|
||||
- release prep 2.7.2 [\#3172](https://github.com/harness/drone/pull/3172) ([eoinmcafee00](https://github.com/eoinmcafee00))
|
||||
|
||||
## [v2.7.1](https://github.com/harness/drone/tree/v2.7.1) (2021-12-17)
|
||||
|
||||
[Full Changelog](https://github.com/harness/drone/compare/v2.7.0...v2.7.1)
|
||||
|
||||
**Fixed bugs:**
|
||||
|
||||
- fixes issue with redirects on double slashes in url [\#3170](https://github.com/harness/drone/pull/3170) ([eoinmcafee00](https://github.com/eoinmcafee00))
|
||||
|
||||
**Merged pull requests:**
|
||||
|
||||
- release prep v2.7.1 [\#3171](https://github.com/harness/drone/pull/3171) ([eoinmcafee00](https://github.com/eoinmcafee00))
|
||||
|
||||
## [v2.7.0](https://github.com/harness/drone/tree/v2.7.0) (2021-12-15)
|
||||
|
||||
[Full Changelog](https://github.com/harness/drone/compare/v2.6.0...v2.7.0)
|
||||
|
||||
**Implemented enhancements:**
|
||||
|
||||
- bump UI to v2.4.1 [\#3167](https://github.com/harness/drone/pull/3167) ([d1wilko](https://github.com/d1wilko))
|
||||
|
||||
**Fixed bugs:**
|
||||
|
||||
- \(DRON-157\) use deploy string in deployment [\#3165](https://github.com/harness/drone/pull/3165) ([tphoney](https://github.com/tphoney))
|
||||
|
||||
**Merged pull requests:**
|
||||
|
||||
- release v2.7.0 [\#3166](https://github.com/harness/drone/pull/3166) ([d1wilko](https://github.com/d1wilko))
|
||||
|
||||
## [v2.6.0](https://github.com/harness/drone/tree/v2.6.0) (2021-11-30)
|
||||
|
||||
[Full Changelog](https://github.com/harness/drone/compare/v2.5.0...v2.6.0)
|
||||
|
||||
**Implemented enhancements:**
|
||||
|
||||
- Feat: implemented gitee client [\#3156](https://github.com/harness/drone/pull/3156) ([kit101](https://github.com/kit101))
|
||||
|
||||
**Merged pull requests:**
|
||||
|
||||
- release prep for v2.6.0 [\#3163](https://github.com/harness/drone/pull/3163) ([tphoney](https://github.com/tphoney))
|
||||
|
||||
## [v2.5.0](https://github.com/harness/drone/tree/v2.5.0) (2021-11-17)
|
||||
|
||||
[Full Changelog](https://github.com/harness/drone/compare/v2.4.0...v2.5.0)
|
||||
|
||||
**Implemented enhancements:**
|
||||
|
||||
- bump ui to v2.4.0 [\#3160](https://github.com/harness/drone/pull/3160) ([eoinmcafee00](https://github.com/eoinmcafee00))
|
||||
- add new endpoint for uploading cards [\#3159](https://github.com/harness/drone/pull/3159) ([eoinmcafee00](https://github.com/eoinmcafee00))
|
||||
- refactor create / find / delete end points for cards [\#3158](https://github.com/harness/drone/pull/3158) ([eoinmcafee00](https://github.com/eoinmcafee00))
|
||||
- bump ui to v2.3.1 [\#3155](https://github.com/harness/drone/pull/3155) ([d1wilko](https://github.com/d1wilko))
|
||||
- provide ability to create/read/store card data in drone server [\#3149](https://github.com/harness/drone/pull/3149) ([eoinmcafee00](https://github.com/eoinmcafee00))
|
||||
- \(DRON-124\) adding new status endpoint [\#3143](https://github.com/harness/drone/pull/3143) ([tphoney](https://github.com/tphoney))
|
||||
|
||||
**Fixed bugs:**
|
||||
|
||||
- fix a typo in readme [\#3150](https://github.com/harness/drone/pull/3150) ([nothatDinger](https://github.com/nothatDinger))
|
||||
|
||||
**Merged pull requests:**
|
||||
|
||||
- release prep for v2.5.0 [\#3161](https://github.com/harness/drone/pull/3161) ([eoinmcafee00](https://github.com/eoinmcafee00))
|
||||
|
||||
## [v2.4.0](https://github.com/harness/drone/tree/v2.4.0) (2021-09-23)
|
||||
|
||||
[Full Changelog](https://github.com/harness/drone/compare/v2.3.1...v2.4.0)
|
||||
|
||||
**Implemented enhancements:**
|
||||
|
||||
- bump ui version to v2.3.0 [\#3146](https://github.com/harness/drone/pull/3146) ([d1wilko](https://github.com/d1wilko))
|
||||
- verify if the application is buildable [\#3144](https://github.com/harness/drone/pull/3144) ([marko-gacesa](https://github.com/marko-gacesa))
|
||||
|
||||
**Fixed bugs:**
|
||||
|
||||
- fixes build issue with bitbucket cloud [\#3147](https://github.com/harness/drone/pull/3147) ([eoinmcafee00](https://github.com/eoinmcafee00))
|
||||
- Fix stepLimit param in Starlark and Template OSS code [\#3141](https://github.com/harness/drone/pull/3141) ([phil-davis](https://github.com/phil-davis))
|
||||
- fix a broken link in readme [\#3140](https://github.com/harness/drone/pull/3140) ([empire](https://github.com/empire))
|
||||
|
||||
**Merged pull requests:**
|
||||
|
||||
- \(maint\)-release 2.4.0 [\#3148](https://github.com/harness/drone/pull/3148) ([d1wilko](https://github.com/d1wilko))
|
||||
- Allow jsonnet imports in pipeline configuration [\#3105](https://github.com/harness/drone/pull/3105) ([hhamalai](https://github.com/hhamalai))
|
||||
|
||||
## [v2.3.1](https://github.com/harness/drone/tree/v2.3.1) (2021-09-09)
|
||||
|
||||
[Full Changelog](https://github.com/harness/drone/compare/v2.3.0...v2.3.1)
|
||||
|
||||
**Implemented enhancements:**
|
||||
|
||||
- bump ui to v2.2.1 - https://github.com/drone/drone-ui/blob/main/CHANGELOG.md [\#3138](https://github.com/harness/drone/pull/3138) ([d1wilko](https://github.com/d1wilko))
|
||||
|
||||
**Merged pull requests:**
|
||||
|
||||
- \(maint\)-release 2.3.1 [\#3139](https://github.com/harness/drone/pull/3139) ([d1wilko](https://github.com/d1wilko))
|
||||
|
||||
## [v2.3.0](https://github.com/harness/drone/tree/v2.3.0) (2021-09-09)
|
||||
|
||||
[Full Changelog](https://github.com/harness/drone/compare/v2.2.0...v2.3.0)
|
||||
|
||||
**Implemented enhancements:**
|
||||
|
||||
- bump ui to v2.2.0 - https://github.com/drone/drone-ui/blob/main/CHANGELOG.md [\#3137](https://github.com/harness/drone/pull/3137) ([d1wilko](https://github.com/d1wilko))
|
||||
- Make starlark step limit configurable [\#3134](https://github.com/harness/drone/pull/3134) ([phil-davis](https://github.com/phil-davis))
|
||||
- \(feat\) drone h/a: wrapped scheduler's signal func with redis mutex [\#3130](https://github.com/harness/drone/pull/3130) ([marko-gacesa](https://github.com/marko-gacesa))
|
||||
|
||||
**Fixed bugs:**
|
||||
|
||||
- \(fix\) trim http/s prefixes from config hostnames [\#3136](https://github.com/harness/drone/pull/3136) ([tphoney](https://github.com/tphoney))
|
||||
- \(fix\) remove unused jwt-go library [\#3129](https://github.com/harness/drone/pull/3129) ([tphoney](https://github.com/tphoney))
|
||||
|
||||
## [v2.2.0](https://github.com/harness/drone/tree/v2.2.0) (2021-09-01)
|
||||
|
||||
[Full Changelog](https://github.com/harness/drone/compare/v2.1.0...v2.2.0)
|
||||
|
||||
**Implemented enhancements:**
|
||||
|
||||
- \(maint\) ui version v2.1.0 - https://github.com/drone/drone-ui/blob/main/CHANGELOG.md [\#3132](https://github.com/harness/drone/pull/3132) ([d1wilko](https://github.com/d1wilko))
|
||||
- Ability to cancel running builds, if a new commit is pushed [\#3126](https://github.com/harness/drone/pull/3126) ([eoinmcafee00](https://github.com/eoinmcafee00))
|
||||
|
||||
**Fixed bugs:**
|
||||
|
||||
- fix templating reg expression to match if .drone.yml contains --- characters [\#3131](https://github.com/harness/drone/pull/3131) ([eoinmcafee00](https://github.com/eoinmcafee00))
|
||||
- add check on template extension type - throw error if invalid [\#3128](https://github.com/harness/drone/pull/3128) ([eoinmcafee00](https://github.com/eoinmcafee00))
|
||||
|
||||
**Merged pull requests:**
|
||||
|
||||
- \(maint\)-release 2.2.0 [\#3133](https://github.com/harness/drone/pull/3133) ([eoinmcafee00](https://github.com/eoinmcafee00))
|
||||
- Rename files with camelCase name to use snake\_case convention [\#3127](https://github.com/harness/drone/pull/3127) ([marko-gacesa](https://github.com/marko-gacesa))
|
||||
- event-stream supports timeout [\#3125](https://github.com/harness/drone/pull/3125) ([zc2638](https://github.com/zc2638))
|
||||
- \(maint\) Readme update Add Contributor Section [\#3111](https://github.com/harness/drone/pull/3111) ([mrsantons](https://github.com/mrsantons))
|
||||
|
||||
## [v2.1.0](https://github.com/harness/drone/tree/v2.1.0) (2021-08-24)
|
||||
|
||||
[Full Changelog](https://github.com/harness/drone/compare/v2.0.6...v2.1.0)
|
||||
|
||||
**Implemented enhancements:**
|
||||
|
||||
- \(maint\) ui version v2.0.1. - https://github.com/drone/drone-ui/blob/main/CHANGELOG.md [\#3123](https://github.com/harness/drone/pull/3123) ([d1wilko](https://github.com/d1wilko))
|
||||
- add support for yaml templates [\#3120](https://github.com/harness/drone/pull/3120) ([eoinmcafee00](https://github.com/eoinmcafee00))
|
||||
|
||||
**Fixed bugs:**
|
||||
|
||||
- Update error message to forbidden if user membership doesn't exist on repo [\#3122](https://github.com/harness/drone/pull/3122) ([eoinmcafee00](https://github.com/eoinmcafee00))
|
||||
- update create template path to have namespace, instead of inside the payload [\#3121](https://github.com/harness/drone/pull/3121) ([eoinmcafee00](https://github.com/eoinmcafee00))
|
||||
- update dependency drone/go-scm to 1.15.2 to fix gitea build problem [\#3118](https://github.com/harness/drone/pull/3118) ([sesky4](https://github.com/sesky4))
|
||||
|
||||
**Merged pull requests:**
|
||||
|
||||
- \(maint\) v2.1.0 release prep [\#3124](https://github.com/harness/drone/pull/3124) ([d1wilko](https://github.com/d1wilko))
|
||||
|
||||
## [v2.0.6](https://github.com/harness/drone/tree/v2.0.6) (2021-08-17)
|
||||
|
||||
[Full Changelog](https://github.com/harness/drone/compare/v2.0.5...v2.0.6)
|
||||
|
||||
**Merged pull requests:**
|
||||
|
||||
- \(maint\) v2.0.6 release prep [\#3119](https://github.com/harness/drone/pull/3119) ([tphoney](https://github.com/tphoney))
|
||||
|
||||
## [v2.0.5](https://github.com/harness/drone/tree/v2.0.5) (2021-08-17)
|
||||
|
||||
[Full Changelog](https://github.com/harness/drone/compare/v2.0.4...v2.0.5)
|
||||
|
||||
**Implemented enhancements:**
|
||||
|
||||
- bump ui version [\#3115](https://github.com/harness/drone/pull/3115) ([d1wilko](https://github.com/d1wilko))
|
||||
- bump ui version [\#3114](https://github.com/harness/drone/pull/3114) ([d1wilko](https://github.com/d1wilko))
|
||||
- Add support for nested data objects within templates [\#3110](https://github.com/harness/drone/pull/3110) ([eoinmcafee00](https://github.com/eoinmcafee00))
|
||||
- \(feat\) redis implementation for pub-sub, log streaming and canceller [\#3108](https://github.com/harness/drone/pull/3108) ([marko-gacesa](https://github.com/marko-gacesa))
|
||||
|
||||
**Fixed bugs:**
|
||||
|
||||
- fix issue where map changes order therefore test randomly fails [\#3112](https://github.com/harness/drone/pull/3112) ([eoinmcafee00](https://github.com/eoinmcafee00))
|
||||
|
||||
**Merged pull requests:**
|
||||
|
||||
- release 2.0.5 [\#3117](https://github.com/harness/drone/pull/3117) ([eoinmcafee00](https://github.com/eoinmcafee00))
|
||||
- Update pull\_request\_template.md [\#3107](https://github.com/harness/drone/pull/3107) ([tphoney](https://github.com/tphoney))
|
||||
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## Unreleased
|
||||
|
||||
## [2.0.4]
|
||||
### Fixed
|
||||
- DRON-97 remove use of request animation frame to prevent high CPU on tab refocus events.
|
||||
|
||||
## [2.0.3]
|
||||
### Fixed
|
||||
- DONE-91 handle extra slashes in url. [#3009](https://github.com/drone/drone/pull/3099).
|
||||
|
||||
## [2.0.2]
|
||||
### Added
|
||||
- Merge remote-tracking branch 'origin/master'
|
||||
- prevent repository list short circuit in UI
|
||||
- remove deprecated steps from building file [#3097](https://github.com/drone/drone/pull/3097)
|
||||
- adding depends_on, image and detached fields to step [#3072](https://github.com/drone/drone/pull/3072)
|
||||
- Add ctx.build.debug boolean [#3082](https://github.com/drone/drone/pull/3082)
|
||||
- Bump github.com/google/go-jsonnet to v0.17.0 [#3084](https://github.com/drone/drone/pull/3084)
|
||||
- bump go-scm v1.15.1 [#3096](https://github.com/drone/drone/pull/3096)
|
||||
- bitbucket server build issue [#3092](https://github.com/drone/drone/pull/3092)
|
||||
- update scm version [#3091](https://github.com/drone/drone/pull/3091)
|
||||
- Limit graceful shutdown duration [#3093](https://github.com/drone/drone/pull/3093)
|
||||
- bump user interface
|
||||
- bump ui version
|
||||
- ignore skip directive for promote and rollback events
|
||||
- new feature: maximum open DB connections is configurable[#3089](https://github.com/drone/drone/pull/3089)
|
||||
- jsonnet additional parameters [#3087](https://github.com/drone/drone/pull/3087)
|
||||
- hide login button if user already authenticated
|
||||
- new feature: configuration templates [#3081](https://github.com/drone/drone/pull/3081)
|
||||
|
||||
### Fixed
|
||||
- various typos [#3088](https://github.com/drone/drone/pull/3088)
|
||||
- handle error properly if template doesn't exist [#3095](https://github.com/drone/drone/pull/3093)
|
||||
- oss build issue [#3086](https://github.com/drone/drone/pull/3086)
|
||||
- graceful shutdown [#3083](https://github.com/drone/drone/pull/3083)
|
||||
|
||||
## [2.0.1]
|
||||
### Added
|
||||
- support for configuring the internal yaml cache size.
|
||||
|
||||
## [2.0.0]
|
||||
### Added
|
||||
- feature flags for mixed-mode database encryption.
|
||||
|
||||
### Changed
|
||||
- user-interface re-design
|
||||
|
||||
### Breaking
|
||||
- removed deprecated kubernetes integration in favor of official kubernetes runner.
|
||||
- removed deprecated nomad integration in favor of official nomad runner.
|
||||
|
||||
## [1.10.1]
|
||||
### Added
|
||||
- support for repository-level concurrency limits.
|
||||
- support for gitlab and github internal visibility on initial sync.
|
||||
|
||||
### Fixed
|
||||
- create machine user with a custom API token.
|
||||
|
||||
## [1.10.0]
|
||||
### Added
|
||||
- support for starlark scripts in core.
|
||||
- support for executing pipelines in debug mode.
|
||||
|
||||
## [1.9.2]
|
||||
### Added
|
||||
- update go-scm dependency to fix
|
||||
|
||||
## [1.9.1]
|
||||
### Added
|
||||
- support for increasing the http request timeout for extensions. [#2998](https://github.com/drone/drone/pull/2998).
|
||||
- support for skipping a pipeline if the validation extension returns an ErrSkip.
|
||||
- support for blocking a pipeline if the validation extension returns an ErrBlock.
|
||||
|
||||
### Fixed
|
||||
- rollback endpoint should be available to users with write permission.
|
||||
- retrying a build should re-use custom build parameters from parent build.
|
||||
|
||||
## [1.9.0] - 2020-07-12
|
||||
### Added
|
||||
- ui support for deployment list and summary.
|
||||
- ui support for promoting and rolling back builds.
|
||||
- feature flag to use static secret when signing webhooks, from @chiraggadasc.
|
||||
|
||||
### Fixed
|
||||
- ui branch list improperly capped.
|
||||
|
||||
### Changed
|
||||
- upgrade drone/envsubst dependency
|
||||
- upgrade drone/go-scm dependency
|
||||
|
||||
## [1.8.1] - 2020-06-23
|
||||
### Fixed
|
||||
- support for gitea api pagination, repository sync hanging.
|
||||
|
||||
## [1.8.0] - 2020-06-10
|
||||
### Added
|
||||
- re-assigned repository ownership when deactivating a user.
|
||||
- re-assigned repository ownership when deleting a user.
|
||||
- de-activate a repository when deleting a user if re-assignment fails.
|
||||
- de-activate a repository when deactivating a user if re-assignment fails.
|
||||
- routine to cleanup builds stuck in a pending state.
|
||||
- routine to cleanup builds stuck in a running state.
|
||||
- private mode setting requires authentication to view public repositories.
|
||||
|
||||
### Fixed
|
||||
- canceling a build emits a sql.ErrNoRows error.
|
||||
- custom token is ignored when creating a user account via the API.
|
||||
- machine accounts with sufficient permissions can create builds via the API.
|
||||
|
||||
### Changed
|
||||
- upgraded Go toolchain to version 1.14.4.
|
||||
|
||||
## [1.7.0] - 2020-03-27
|
||||
### Added
|
||||
- endpoint to display the latest build by branch. [#2940](https://github.com/drone/drone/pull/2940).
|
||||
- endpoint to display the latest build by pull request. [#2940](https://github.com/drone/drone/pull/2940).
|
||||
- endpoint to display the latest build by environment. [#2940](https://github.com/drone/drone/pull/2940).
|
||||
- endpoint to delete a branch from the index. [#2940](https://github.com/drone/drone/pull/2940).
|
||||
- endpoint to delete a pull request from the index. [#2940](https://github.com/drone/drone/pull/2940).
|
||||
- endpoint to delete an environment from the index. [#2940](https://github.com/drone/drone/pull/2940).
|
||||
- page to view the latest build per branch.
|
||||
|
||||
### Fixed
|
||||
- sync routine not executing asynchronously, being cancelled by http context.
|
||||
- sync routine should ignore gitlab subrepositories
|
||||
- convert deploy events in 0.8 yaml to promote events.
|
||||
- do not execute cron job for disabled repositories. [#2931](https://github.com/drone/drone/issues/2931).
|
||||
- remove trailing slash from gitea url to prevent oauth2 token refresh errors, by [@cmj0121](https://github.com/cmj0121). [#2920](https://github.com/drone/drone/issues/2920).
|
||||
- disable font ligatures in build log output. [drone/drone-ui#322](https://github.com/drone/drone-ui/pull/322).
|
||||
- missing am/pm in timestamps
|
||||
|
||||
## [1.6.5] - 2020-01-29
|
||||
### Changed
|
||||
- update version of go-scm
|
||||
- update alpine version in docker images
|
||||
- use ticker for cron jobs for more accurate timing
|
||||
|
||||
## [1.6.4] - 2019-12-30
|
||||
### Added
|
||||
- optionally enable pprof endpoints for profiling, by [@bradrydzewski](https://github.com/bradrydzewski).
|
||||
|
||||
## [1.6.3] - 2019-12-10
|
||||
### Fixed
|
||||
- disable caching generated yaml files by commit sha, by [@bradrydzewski](https://github.com/bradrydzewski).
|
||||
|
||||
### Added
|
||||
- support for bitbucket skipverify, by [@toni-moreno](https://github.com/toni-moreno).
|
||||
- support for gitea skipverify, by [@toni-moreno](https://github.com/toni-moreno).
|
||||
|
||||
## [1.6.2] - 2019-11-08
|
||||
### Added
|
||||
- support for loading license contents from env, by [@bradrydzewski](https://github.com/bradrydzewski).
|
||||
|
||||
### Fixed
|
||||
- regression not converting legacy pipeline when using new runners, by [@bradrydzewski](https://github.com/bradrydzewski).
|
||||
|
||||
## [1.6.1] - 2019-10-17
|
||||
### Added
|
||||
- updated autocert library in support of acme v2 protocol, by [@bradrydzewski](https://github.com/bradrydzewski).
|
||||
|
||||
### Fixed
|
||||
- fixed nil pointer when manually adding user from api, by [@bradrydzewski](https://github.com/bradrydzewski).
|
||||
|
||||
## [1.6.0] - 2019-10-04
|
||||
### Added
|
||||
- added nsswitch to docker images
|
||||
- option to auto-cancel pending builds when newer build enqueued, by [@bradrydzewski](https://github.com/bradrydzewski). [#1980](https://github.com/drone/drone/issues/1980).
|
||||
- endpoint to list all repositories in the database, by [@bradrydzewski](https://github.com/bradrydzewski). [#2785](https://github.com/drone/drone/issues/2785).
|
||||
|
||||
### Fixed
|
||||
- improve sync to handle duplicate repository names with different unique identifiers, by [@bradrydzewski](https://github.com/bradrydzewski). [#2658](https://github.com/drone/drone/issues/2658). _You can revert to the previous sync logic with DRONE_DATABASE_LEGACY_BATCH=true_.
|
||||
|
||||
## [1.5.1] - 2019-09-30
|
||||
### Added
|
||||
- allow organization admins access to organization secret endpoints, by [@bradrydzewski](https://github.com/bradrydzewski). [#2838](https://github.com/drone/drone/issues/2838).
|
||||
|
||||
### Fixed
|
||||
- fix invalid deep links in UI for github enterprise, by [@bradrydzewski](https://github.com/bradrydzewski).
|
||||
- ensure correct casing when manually adding user, by [@bradrydzewski](https://github.com/bradrydzewski). [#2766](https://github.com/drone/drone/issues/2766).
|
||||
|
||||
## [1.5.0] - 2019-09-28
|
||||
### Added
|
||||
- endpoint to execute a cron pipeline on-demand, by [@bradrydzewski](https://github.com/bradrydzewski). [#2781](https://github.com/drone/drone/issues/2781).
|
||||
- endpoint to list builds by branch, by [@bradrydzewski](https://github.com/bradrydzewski). [#1495](https://github.com/drone/drone/issues/1495).
|
||||
- ignore skip comments when cron event, by [@bradrydzewski](https://github.com/bradrydzewski). [#2835](https://github.com/drone/drone/issues/2835).
|
||||
- support for admission extensions, by [@bradrydzewski](https://github.com/bradrydzewski). [#2043](https://github.com/drone/drone/issues/2043).
|
||||
- endpoint to provide link to git resources, by [@bradrydzewski](https://github.com/bradrydzewski). [#2843](https://github.com/drone/drone/issues/2843).
|
||||
- improve bitbucket status display text on new pull request screen, by [@bradrydzewski](https://github.com/bradrydzewski).
|
||||
|
||||
### Fixed
|
||||
- missing cron job name in user interface, by [@bradrydzewski](https://github.com/bradrydzewski).
|
||||
- log lines not properly wrapping in user interface, by [@bradrydzewski](https://github.com/bradrydzewski).
|
||||
[#309](https://github.com/drone/drone-ui/issues/309).
|
||||
|
||||
### Breaking
|
||||
- the server now runs in multi-machine mode by default. In order to run the server in single-machine mode (agents disabled) you must set DRONE_AGENTS_DISABLED=true.
|
||||
|
||||
## [1.4.0] - 2019-09-12
|
||||
### Added
|
||||
- upgrade to Go 1.13 to resolve arm segfault, by [@KN4CK3R](https://github.com/KN4CK3R). [#2823](https://github.com/drone/drone/issues/2823).
|
||||
- configure default visibility, by [@JordanSussman](https://github.com/JordanSussman). [#2824](https://github.com/drone/drone/issues/2824).
|
||||
- configure default trusted flag, by [@vyckou](https://github.com/vyckou).
|
||||
- support for validation plugins, by [@bradrydzewski](https://github.com/bradrydzewski). [#2266](https://github.com/drone/drone/issues/2266).
|
||||
- support for conversion plugins, by [@bradrydzewski](https://github.com/bradrydzewski).
|
||||
- support for cron event type, by [@bradrydzewski](https://github.com/bradrydzewski). [#2705](https://github.com/drone/drone/issues/2705).
|
||||
- support for rollback event, by [@bradrydzewski](https://github.com/bradrydzewski). [#2695](https://github.com/drone/drone/issues/2695).
|
||||
- support for lets encrypt email, by [@bradrydzewski](https://github.com/bradrydzewski). [#2505](https://github.com/drone/drone/issues/2505).
|
||||
|
||||
### Removed
|
||||
- Support for basic auth as an option for Gitea, by [@techknowlogick](https://giteahub.com/techknowlogick). [#2721](https://github.com/drone/drone/issues/2721)
|
||||
|
||||
### Fixed
|
||||
- copy cron job name when restarting a cron job, by [@bradrydzewski](https://github.com/bradrydzewski). [#2760](https://github.com/drone/drone/issues/2760).
|
||||
|
||||
## [1.3.1] - 2019-08-26
|
||||
### Added
|
||||
- support for the GitHub deployment status API, by [@bradrydzewski](https://github.com/bradrydzewski).
|
||||
|
||||
## [1.3.0] - 2019-08-20
|
||||
### Added
|
||||
- support for storing logs in Azure Cloud Storage, by [@Lucretius](https://github.com/Lucretius). [#2788](https://github.com/drone/drone/pull/2788)
|
||||
- support for windows server 1903, by [@bradrydzewski](https://github.com/bradrydzewski).
|
||||
- button to view the full log file, by [@dramich](https://github.com/dramich). [drone/drone-ui#287](https://github.com/drone/drone-ui/pull/287).
|
||||
|
||||
### Fixed
|
||||
- read gogs sha from webhook, by [@marcotuna](https://github.com/marcotuna).
|
||||
- create bind volume on host if not exists, by [@bradrydzewski](https://github.com/bradrydzewski). [#2725](https://github.com/drone/drone/issues/2725).
|
||||
- preserve whitespace in build logs, by [@geek1011](https://github.com/geek1011). [drone/drone-ui#294](https://github.com/drone/drone-ui/pull/294).
|
||||
- enable log file download on firefox, by [@bobmanary](https://github.com/bobmanary). [drone/drone-ui#303](https://github.com/drone/drone-ui/pull/303)
|
||||
|
||||
### Security
|
||||
- upgraded to Go 1.12.9 due to CVE-2019-9512 and CVE-2019-9514
|
||||
|
||||
## [1.2.3] - 2019-07-30
|
||||
### Added
|
||||
|
||||
- disable github status for cron jobs
|
||||
- support for action in conditionals, by [@bradrydzewski](https://github.com/bradrydzewski). [#2685](https://github.com/drone/drone/issues/2685).
|
||||
|
||||
### Fixed
|
||||
|
||||
- improve cancel logic for dangling stages, by [@bradrydzewski](https://github.com/bradrydzewski).
|
||||
- improve error when kubernetes malforms the port configuration, by [@bradrydzewski](https://github.com/bradrydzewski). [#2742](https://github.com/drone/drone/issues/2742).
|
||||
- copy parameters from parent build when promoting, by [@bradrydzewski](https://github.com/bradrydzewski). [#2748](https://github.com/drone/drone/issues/2748).
|
||||
|
||||
## [1.2.2] - 2019-07-29
|
||||
### Added
|
||||
|
||||
- support for legacy environment variables
|
||||
- support for legacy workspace based on repository name
|
||||
- support for github deployment hooks
|
||||
- provide base sha for github pull requests
|
||||
- option to filter webhooks by event and type
|
||||
- upgrade drone-yaml to v1.2.2
|
||||
- upgrade drone-runtime to v1.0.7
|
||||
|
||||
### Fixed
|
||||
|
||||
- error when manually creating an empty user, by [@bradrydzewski](https://github.com/bradrydzewski). [#2738](https://github.com/drone/drone/issues/2738).
|
||||
|
||||
## [1.2.1] - 2019-06-11
|
||||
### Added
|
||||
|
||||
- support for legacy tokens to ease upgrade path, by [@bradrydzewski](https://github.com/bradrydzewski). [#2713](https://github.com/drone/drone/issues/2713).
|
||||
- include repository name and id in batch update error message, by [@bradrydzewski](https://github.com/bradrydzewski).
|
||||
|
||||
### Fixed
|
||||
|
||||
- fix inconsistent base64 encoding and decoding of encrypted secrets, by [@bradrydzewski](https://github.com/bradrydzewski).
|
||||
- update drone-yaml to version 1.1.2 for improved 0.8 to 1.0 yaml marshal escaping.
|
||||
- update drone-yaml to version 1.1.3 for improved 0.8 to 1.0 workspace conversion.
|
||||
|
||||
## [1.2.0] - 2019-05-30
|
||||
### Added
|
||||
|
||||
- endpoint to trigger new build for default branch, by [@bradrydzewski](https://github.com/bradrydzewski). [#2679](https://github.com/drone/drone/issues/2679).
|
||||
- endpoint to trigger new build for branch, by [@bradrydzewski](https://github.com/bradrydzewski). [#2679](https://github.com/drone/drone/issues/2679).
|
||||
- endpoint to trigger new build for branch and sha, by [@bradrydzewski](https://github.com/bradrydzewski). [#2679](https://github.com/drone/drone/issues/2679).
|
||||
- enable optional prometheus metrics guest access, by [@janberktold](https://github.com/janberktold)
|
||||
- fallback to database when logs not found in s3, by [@bradrydzewski](https://github.com/bradrydzewski). [#2689](https://github.com/drone/drone/issues/2689).
|
||||
- support for custom stage definitions and runners, by [@bradrydzewski](https://github.com/bradrydzewski). [#2680](https://github.com/drone/drone/issues/2680).
|
||||
- update drone-yaml to version 1.1.0
|
||||
|
||||
### Fixed
|
||||
|
||||
- retrieve latest build by branch, by [@tboerger](https://github.com/tboerger).
|
||||
- copy the fork value when restarting a build, by [@bradrydzewski](https://github.com/bradrydzewski). [#2708](https://github.com/drone/drone/issues/2708).
|
||||
- make healthz available without redirect, by [@bradrydzewski](https://github.com/bradrydzewski). [#2706](https://github.com/drone/drone/issues/2706).
|
||||
|
||||
## [1.1.0] - 2019-04-23
|
||||
### Added
|
||||
|
||||
- specify a user for the pipeline step, by [@bradrydzewski](https://github.com/bradrydzewski). [#2651](https://github.com/drone/drone/issues/2651).
|
||||
- support for Gitea oauth2, by [@techknowlogick](https://github.com/techknowlogick). [#2622](https://github.com/drone/drone/pull/2622).
|
||||
- ping the docker daemon before starting the agent, by [@bradrydzewski](https://github.com/bradrydzewski). [#2495](https://github.com/drone/drone/issues/2495).
|
||||
- support for Cron job name in Yaml trigger block, by [@bradrydzewski](https://github.com/bradrydzewski). [#2628](https://github.com/drone/drone/issues/2628).
|
||||
- support for Cron job name in Yaml when block, by [@bradrydzewski](https://github.com/bradrydzewski). [#2628](https://github.com/drone/drone/issues/2628).
|
||||
- sqlite username column changed to case-insensitive, by [@bradrydzewski](https://github.com/bradrydzewski).
|
||||
- endpoint to purge repository from database, by [@bradrydzewski](https://github.com/bradrydzewski).
|
||||
- support for per-organization secrets, by [@bradrydzewski](https://github.com/bradrydzewski).
|
||||
- include system metadata in global webhooks, by [@bradrydzewski](https://github.com/bradrydzewski).
|
||||
- ability to customize cookie secure flag, by [@bradrydzewski](https://github.com/bradrydzewski).
|
||||
- update drone-yaml from version 1.0.6 to 1.0.8.
|
||||
- update drone-runtime from version 1.0.4 to 1.0.6.
|
||||
- update go-scm from version 1.0.3 to 1.0.4.
|
||||
|
||||
### Fixed
|
||||
|
||||
- fixed error in mysql table creation syntax, from [@xuyang2](https://github.com/xuyang2). [#2677](https://github.com/drone/drone/pull/2677).
|
||||
- fixed stuck builds when upstream dependency is skipped, from [@bradrydzewski](https://github.com/bradrydzewski). [#2634](https://github.com/drone/drone/issues/2634).
|
||||
- fixed issue running steps with dependencies on failure, from [@bradrydzewski](https://github.com/bradrydzewski). [#2667](https://github.com/drone/drone/issues/2667).
|
||||
|
||||
## [1.0.1] - 2019-04-10
|
||||
### Added
|
||||
|
||||
- pass stage environment variables to pipeline steps, by [@bradrydzewski](https://github.com/bradrydzewski).
|
||||
- update go-scm to version 1.3.0, by [@bradrydzewski](https://github.com/bradrydzewski).
|
||||
- update drone-runtime to version to 1.0.4, by [@bradrydzewski](https://github.com/bradrydzewski).
|
||||
- ping docker daemon before agent starts to ensure connectivity, by [@bradrydzewski](https://github.com/bradrydzewski).
|
||||
|
||||
|
||||
\* *This Changelog was automatically generated by [github_changelog_generator](https://github.com/github-changelog-generator/github-changelog-generator)*
|
||||
|
|
@ -1,69 +0,0 @@
|
|||
# Contributing to Harness
|
||||
|
||||
Thank you for your interest in open source contributions to Harness. Harness uses GitHub to manage open source reviews of pull requests.
|
||||
|
||||
* If you are a new contributor see: [Steps to Contribute](#steps-to-contribute)
|
||||
|
||||
* If you have a minor fix or improvement, feel free to create a pull request. Please provide necessary details in the pull request description and use a meaningful title.
|
||||
|
||||
* If you plan to do something more involved, first discuss your ideas by [raising an issue](https://github.com/harness/harness/issues). This will avoid unnecessary work and surely give you and us a good deal of inspiration.
|
||||
|
||||
* Relevant coding style guidelines are
|
||||
|
||||
- For backend: the [Go Code Review Comments](https://code.google.com/p/go-wiki/wiki/CodeReviewComments) and the formatting and style section of Peter Bourgon's [Go: Best Practices for Production Environments](https://peter.bourgon.org/go-in-production/#formatting-and-style)
|
||||
- For frontend: [Google TypeScript Style Guide](https://google.github.io/styleguide/tsguide.html) and [Best practices for Typescript coding](https://medium.com/@eshagarg1996/best-practices-for-typescript-coding-8b1ea98d02f8).
|
||||
|
||||
* Be sure to sign off on the [CLA](https://cla-assistant.io/harness/gitness).
|
||||
|
||||
## Steps to Contribute
|
||||
|
||||
Should you wish to work on an issue, please claim it first by commenting on the GitHub issue that you want to work on. This is to prevent duplicated efforts from contributors on the same issue.
|
||||
|
||||
Please check the [`good-first-issue`](https://github.com/harness/harness/issues?q=is%3Aissue+is%3Aopen+label%3A%22good+first+issue%22) label to find issues that are good for getting started. If you have questions about one of the issues, with or without the tag, please comment on them and one of the maintainers will clarify it. For a quicker response, contact us over [slack](https://developer.harness.io/docs/open-source/support#slack).
|
||||
|
||||
### Local Development
|
||||
|
||||
Please review [Harness development](https://github.com/harness/harness/tree/main?tab=readme-ov-file#harness-development) to build and test your code locally.
|
||||
|
||||
### Pre-commit Hook
|
||||
|
||||
We have a pre-commit hook to ensure code quality before committing changes. This hook checks for required binaries (grep, sed, and xargs) and runs checks specifically for Go files (*.go). If any issues are found during the checks, the commit process will be halted until the issues are resolved.
|
||||
|
||||
### Lint Check
|
||||
|
||||
Our CI Linter pipeline conducts automated checks for code quality, with [separate lint checks for Go and TypeScript](https://github.com/harness/harness/blob/main/.github/workflows/ci-lint.yml). These checks help ensure adherence to coding standards and identify potential issues early in the development process. Thank you for contributing to our code quality efforts!
|
||||
|
||||
## Pull Request Checklist
|
||||
|
||||
* Branch from the main branch and, if needed, rebase to the current main branch before submitting your pull request. If it doesn't merge cleanly with main you may be asked to rebase your changes.
|
||||
|
||||
* Commits should be as small as possible, while ensuring that each commit is correct independently (i.e., each commit should compile and pass tests).
|
||||
|
||||
* If your patch is not getting reviewed or you need a specific person to review it, you can @-reply a reviewer asking for a review in the pull request or a comment.
|
||||
|
||||
* Add tests relevant to the fixed bug or new feature.
|
||||
|
||||
## Dependency management
|
||||
|
||||
Harness uses [Go modules](https://golang.org/cmd/go/#hdr-Modules__module_versions__and_more) to manage dependencies on external packages.
|
||||
|
||||
To add or update a new dependency, use the `go get` command:
|
||||
|
||||
```bash
|
||||
# Pick the latest tagged release.
|
||||
go get example.com/some/module/pkg@latest
|
||||
|
||||
# Pick a specific version.
|
||||
go get example.com/some/module/pkg@vX.Y.Z
|
||||
```
|
||||
|
||||
Tidy up the `go.mod` and `go.sum` files:
|
||||
|
||||
```bash
|
||||
# The GO111MODULE variable can be omitted when the code isn't located in GOPATH.
|
||||
GO111MODULE=on go mod tidy
|
||||
```
|
||||
|
||||
You have to commit the changes to `go.mod` and `go.sum` before submitting the pull request.
|
||||
|
||||
|
||||
96
Dockerfile
96
Dockerfile
|
|
@ -1,96 +0,0 @@
|
|||
# ---------------------------------------------------------#
|
||||
# Build web image #
|
||||
# ---------------------------------------------------------#
|
||||
FROM --platform=$BUILDPLATFORM node:16 as web
|
||||
|
||||
WORKDIR /usr/src/app
|
||||
|
||||
COPY web/package.json ./
|
||||
COPY web/yarn.lock ./
|
||||
|
||||
# If you are building your code for production
|
||||
# RUN npm ci --omit=dev
|
||||
|
||||
COPY ./web .
|
||||
|
||||
RUN yarn && yarn build && yarn cache clean
|
||||
|
||||
# ---------------------------------------------------------#
|
||||
# Build Harness image #
|
||||
# ---------------------------------------------------------#
|
||||
FROM --platform=$BUILDPLATFORM golang:1.24.9-alpine3.22 as builder
|
||||
|
||||
RUN apk update \
|
||||
&& apk add --no-cache protoc build-base git
|
||||
|
||||
# Setup workig dir
|
||||
WORKDIR /app
|
||||
RUN git config --global --add safe.directory '/app'
|
||||
|
||||
# Get dependencies - will also be cached if we won't change mod/sum
|
||||
COPY go.mod .
|
||||
COPY go.sum .
|
||||
|
||||
COPY Makefile .
|
||||
ENV CGO_CFLAGS="-D_LARGEFILE64_SOURCE"
|
||||
RUN make dep
|
||||
RUN make tools
|
||||
# COPY the source code as the last step
|
||||
COPY . .
|
||||
|
||||
COPY --from=web /usr/src/app/dist /app/web/dist
|
||||
|
||||
# build
|
||||
ARG GIT_COMMIT
|
||||
ARG GITNESS_VERSION_MAJOR
|
||||
ARG GITNESS_VERSION_MINOR
|
||||
ARG GITNESS_VERSION_PATCH
|
||||
ARG TARGETOS TARGETARCH
|
||||
|
||||
RUN if [ "$TARGETARCH" = "arm64" ]; then \
|
||||
wget -P ~ https://musl.cc/aarch64-linux-musl-cross.tgz && \
|
||||
tar -xvf ~/aarch64-linux-musl-cross.tgz -C ~ ; \
|
||||
fi
|
||||
|
||||
# set required build flags
|
||||
RUN --mount=type=cache,target=/root/.cache/go-build \
|
||||
--mount=type=cache,target=/go/pkg \
|
||||
if [ "$TARGETARCH" = "arm64" ]; then CC=~/aarch64-linux-musl-cross/bin/aarch64-linux-musl-gcc; fi && \
|
||||
LDFLAGS="-X github.com/harness/gitness/version.GitCommit=${GIT_COMMIT} -X github.com/harness/gitness/version.major=${GITNESS_VERSION_MAJOR} -X github.com/harness/gitness/version.minor=${GITNESS_VERSION_MINOR} -X github.com/harness/gitness/version.patch=${GITNESS_VERSION_PATCH} -extldflags '-static'" && \
|
||||
CGO_ENABLED=1 \
|
||||
GOOS=$TARGETOS GOARCH=$TARGETARCH \
|
||||
CC=$CC go build -ldflags="$LDFLAGS" -o ./gitness ./cmd/gitness
|
||||
|
||||
### Pull CA Certs
|
||||
FROM --platform=$BUILDPLATFORM alpine:latest as cert-image
|
||||
|
||||
RUN apk --update add ca-certificates
|
||||
|
||||
# ---------------------------------------------------------#
|
||||
# Create final image #
|
||||
# ---------------------------------------------------------#
|
||||
FROM --platform=$TARGETPLATFORM alpine/git:2.49.1 as final
|
||||
|
||||
# setup app dir and its content
|
||||
WORKDIR /app
|
||||
VOLUME /data
|
||||
|
||||
ENV XDG_CACHE_HOME /data
|
||||
ENV GITNESS_GIT_ROOT /data
|
||||
ENV GITNESS_REGISTRY_FILESYSTEM_ROOT_DIRECTORY /data/registry
|
||||
ENV GITNESS_DATABASE_DRIVER sqlite3
|
||||
ENV GITNESS_DATABASE_DATASOURCE /data/database.sqlite
|
||||
ENV GITNESS_METRIC_ENABLED=true
|
||||
ENV GITNESS_METRIC_ENDPOINT=https://stats.drone.ci/api/v1/gitness
|
||||
ENV GITNESS_TOKEN_COOKIE_NAME=token
|
||||
ENV GITNESS_DOCKER_API_VERSION 1.41
|
||||
ENV GITNESS_SSH_ENABLE=true
|
||||
ENV GITNESS_GITSPACE_ENABLE=true
|
||||
|
||||
COPY --from=builder /app/gitness /app/gitness
|
||||
COPY --from=cert-image /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ca-certificates.crt
|
||||
|
||||
EXPOSE 3000
|
||||
EXPOSE 3022
|
||||
|
||||
ENTRYPOINT [ "/app/gitness", "server" ]
|
||||
|
|
@ -1,86 +0,0 @@
|
|||
# ---------------------------------------------------------#
|
||||
# Pull UIv2 image #
|
||||
# ---------------------------------------------------------#
|
||||
|
||||
# opensource-ui is only pushed as linux/arm64 - okay since we only copy files.
|
||||
FROM --platform=linux/arm64 harness/opensource-ui:standalone.alpha.480 as uiv2
|
||||
|
||||
# ---------------------------------------------------------#
|
||||
# Build Harness image #
|
||||
# ---------------------------------------------------------#
|
||||
FROM --platform=$BUILDPLATFORM golang:1.24.9-alpine3.22 as builder
|
||||
|
||||
RUN apk update \
|
||||
&& apk add --no-cache protoc build-base git
|
||||
|
||||
# Setup workig dir
|
||||
WORKDIR /app
|
||||
RUN git config --global --add safe.directory '/app'
|
||||
|
||||
# Get dependencies - will also be cached if we won't change mod/sum
|
||||
COPY go.mod .
|
||||
COPY go.sum .
|
||||
|
||||
COPY Makefile .
|
||||
ENV CGO_CFLAGS="-D_LARGEFILE64_SOURCE"
|
||||
RUN make dep
|
||||
RUN make tools
|
||||
# COPY the source code as the last step
|
||||
COPY . .
|
||||
|
||||
COPY --from=uiv2 /canary-dist /app/web/dist
|
||||
|
||||
# build
|
||||
ARG GIT_COMMIT
|
||||
ARG GITNESS_VERSION_MAJOR
|
||||
ARG GITNESS_VERSION_MINOR
|
||||
ARG GITNESS_VERSION_PATCH
|
||||
ARG TARGETOS TARGETARCH
|
||||
|
||||
RUN if [ "$TARGETARCH" = "arm64" ]; then \
|
||||
wget -P ~ https://musl.cc/aarch64-linux-musl-cross.tgz && \
|
||||
tar -xvf ~/aarch64-linux-musl-cross.tgz -C ~ ; \
|
||||
fi
|
||||
|
||||
# set required build flags
|
||||
RUN --mount=type=cache,target=/root/.cache/go-build \
|
||||
--mount=type=cache,target=/go/pkg \
|
||||
if [ "$TARGETARCH" = "arm64" ]; then CC=~/aarch64-linux-musl-cross/bin/aarch64-linux-musl-gcc; fi && \
|
||||
LDFLAGS="-X github.com/harness/gitness/version.GitCommit=${GIT_COMMIT} -X github.com/harness/gitness/version.major=${GITNESS_VERSION_MAJOR} -X github.com/harness/gitness/version.minor=${GITNESS_VERSION_MINOR} -X github.com/harness/gitness/version.patch=${GITNESS_VERSION_PATCH} -extldflags '-static'" && \
|
||||
CGO_ENABLED=1 \
|
||||
GOOS=$TARGETOS GOARCH=$TARGETARCH \
|
||||
CC=$CC go build -ldflags="$LDFLAGS" -o ./gitness ./cmd/gitness
|
||||
|
||||
### Pull CA Certs
|
||||
FROM --platform=$BUILDPLATFORM alpine:latest as cert-image
|
||||
|
||||
RUN apk --update add ca-certificates
|
||||
|
||||
# ---------------------------------------------------------#
|
||||
# Create final image #
|
||||
# ---------------------------------------------------------#
|
||||
FROM --platform=$TARGETPLATFORM alpine/git:2.49.1 as final
|
||||
|
||||
# setup app dir and its content
|
||||
WORKDIR /app
|
||||
VOLUME /data
|
||||
|
||||
ENV XDG_CACHE_HOME /data
|
||||
ENV GITNESS_GIT_ROOT /data
|
||||
ENV GITNESS_REGISTRY_FILESYSTEM_ROOT_DIRECTORY /data/registry
|
||||
ENV GITNESS_DATABASE_DRIVER sqlite3
|
||||
ENV GITNESS_DATABASE_DATASOURCE /data/database.sqlite
|
||||
ENV GITNESS_METRIC_ENABLED=true
|
||||
ENV GITNESS_METRIC_ENDPOINT=https://stats.drone.ci/api/v1/gitness
|
||||
ENV GITNESS_TOKEN_COOKIE_NAME=token
|
||||
ENV GITNESS_DOCKER_API_VERSION 1.41
|
||||
ENV GITNESS_SSH_ENABLE=true
|
||||
ENV GITNESS_GITSPACE_ENABLE=true
|
||||
|
||||
COPY --from=builder /app/gitness /app/gitness
|
||||
COPY --from=cert-image /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ca-certificates.crt
|
||||
|
||||
EXPOSE 3000
|
||||
EXPOSE 3022
|
||||
|
||||
ENTRYPOINT [ "/app/gitness", "server" ]
|
||||
|
|
@ -0,0 +1,326 @@
|
|||
# Changelog
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## Unreleased
|
||||
|
||||
## [2.0.4]
|
||||
### Fixed
|
||||
- DRON-97 remove use of request animation frame to prevent high CPU on tab refocus events.
|
||||
|
||||
## [2.0.3]
|
||||
### Fixed
|
||||
- DONE-91 handle extra slashes in url. [#3009](https://github.com/drone/drone/pull/3099).
|
||||
|
||||
## [2.0.2]
|
||||
### Added
|
||||
- Merge remote-tracking branch 'origin/master'
|
||||
- prevent repository list short circuit in UI
|
||||
- remove deprecated steps from building file [#3097](https://github.com/drone/drone/pull/3097)
|
||||
- adding depends_on, image and detached fields to step [#3072](https://github.com/drone/drone/pull/3072)
|
||||
- Add ctx.build.debug boolean [#3082](https://github.com/drone/drone/pull/3082)
|
||||
- Bump github.com/google/go-jsonnet to v0.17.0 [#3084](https://github.com/drone/drone/pull/3084)
|
||||
- bump go-scm v1.15.1 [#3096](https://github.com/drone/drone/pull/3096)
|
||||
- bitbucket server build issue [#3092](https://github.com/drone/drone/pull/3092)
|
||||
- update scm version [#3091](https://github.com/drone/drone/pull/3091)
|
||||
- Limit graceful shutdown duration [#3093](https://github.com/drone/drone/pull/3093)
|
||||
- bump user interface
|
||||
- bump ui version
|
||||
- ignore skip directive for promote and rollback events
|
||||
- new feature: maximum open DB connections is configurable[#3089](https://github.com/drone/drone/pull/3089)
|
||||
- jsonnet additional parameters [#3087](https://github.com/drone/drone/pull/3087)
|
||||
- hide login button if user already authenticated
|
||||
- new feature: configuration templates [#3081](https://github.com/drone/drone/pull/3081)
|
||||
|
||||
### Fixed
|
||||
- various typos [#3088](https://github.com/drone/drone/pull/3088)
|
||||
- handle error properly if template doesn't exist [#3095](https://github.com/drone/drone/pull/3093)
|
||||
- oss build issue [#3086](https://github.com/drone/drone/pull/3086)
|
||||
- graceful shutdown [#3083](https://github.com/drone/drone/pull/3083)
|
||||
|
||||
## [2.0.1]
|
||||
### Added
|
||||
- support for configuring the internal yaml cache size.
|
||||
|
||||
## [2.0.0]
|
||||
### Added
|
||||
- feature flags for mixed-mode database encryption.
|
||||
|
||||
### Changed
|
||||
- user-interface re-design
|
||||
|
||||
### Breaking
|
||||
- removed deprecated kubernetes integration in favor of official kubernetes runner.
|
||||
- removed deprecated nomad integration in favor of official nomad runner.
|
||||
|
||||
## [1.10.1]
|
||||
### Added
|
||||
- support for repository-level concurrency limits.
|
||||
- support for gitlab and github internal visibility on initial sync.
|
||||
|
||||
### Fixed
|
||||
- create machine user with a custom API token.
|
||||
|
||||
## [1.10.0]
|
||||
### Added
|
||||
- support for starlark scripts in core.
|
||||
- support for executing pipelines in debug mode.
|
||||
|
||||
## [1.9.2]
|
||||
### Added
|
||||
- update go-scm dependency to fix
|
||||
|
||||
## [1.9.1]
|
||||
### Added
|
||||
- support for increasing the http request timeout for extensions. [#2998](https://github.com/drone/drone/pull/2998).
|
||||
- support for skipping a pipeline if the validation extension returns an ErrSkip.
|
||||
- support for blocking a pipeline if the validation extension returns an ErrBlock.
|
||||
|
||||
### Fixed
|
||||
- rollback endpoint should be available to users with write permission.
|
||||
- retrying a build should re-use custom build parameters from parent build.
|
||||
|
||||
## [1.9.0] - 2020-07-12
|
||||
### Added
|
||||
- ui support for deployment list and summary.
|
||||
- ui support for promoting and rolling back builds.
|
||||
- feature flag to use static secret when signing webhooks, from @chiraggadasc.
|
||||
|
||||
### Fixed
|
||||
- ui branch list improperly capped.
|
||||
|
||||
### Changed
|
||||
- upgrade drone/envsubst dependency
|
||||
- upgrade drone/go-scm dependency
|
||||
|
||||
## [1.8.1] - 2020-06-23
|
||||
### Fixed
|
||||
- support for gitea api pagination, repository sync hanging.
|
||||
|
||||
## [1.8.0] - 2020-06-10
|
||||
### Added
|
||||
- re-assigned repository ownership when deactivating a user.
|
||||
- re-assigned repository ownership when deleting a user.
|
||||
- de-activate a repository when deleting a user if re-assignment fails.
|
||||
- de-activate a repository when deactivating a user if re-assignment fails.
|
||||
- routine to cleanup builds stuck in a pending state.
|
||||
- routine to cleanup builds stuck in a running state.
|
||||
- private mode setting requires authentication to view public repositories.
|
||||
|
||||
### Fixed
|
||||
- canceling a build emits a sql.ErrNoRows error.
|
||||
- custom token is ignored when creating a user account via the API.
|
||||
- machine accounts with sufficient permissions can create builds via the API.
|
||||
|
||||
### Changed
|
||||
- upgraded Go toolchain to version 1.14.4.
|
||||
|
||||
## [1.7.0] - 2020-03-27
|
||||
### Added
|
||||
- endpoint to display the latest build by branch. [#2940](https://github.com/drone/drone/pull/2940).
|
||||
- endpoint to display the latest build by pull request. [#2940](https://github.com/drone/drone/pull/2940).
|
||||
- endpoint to display the latest build by environment. [#2940](https://github.com/drone/drone/pull/2940).
|
||||
- endpoint to delete a branch from the index. [#2940](https://github.com/drone/drone/pull/2940).
|
||||
- endpoint to delete a pull request from the index. [#2940](https://github.com/drone/drone/pull/2940).
|
||||
- endpoint to delete an environment from the index. [#2940](https://github.com/drone/drone/pull/2940).
|
||||
- page to view the latest build per branch.
|
||||
|
||||
### Fixed
|
||||
- sync routine not executing asynchronously, being cancelled by http context.
|
||||
- sync routine should ignore gitlab subrepositories
|
||||
- convert deploy events in 0.8 yaml to promote events.
|
||||
- do not execute cron job for disabled repositories. [#2931](https://github.com/drone/drone/issues/2931).
|
||||
- remove trailing slash from gitea url to prevent oauth2 token refresh errors, by [@cmj0121](https://github.com/cmj0121). [#2920](https://github.com/drone/drone/issues/2920).
|
||||
- disable font ligatures in build log output. [drone/drone-ui#322](https://github.com/drone/drone-ui/pull/322).
|
||||
- missing am/pm in timestamps
|
||||
|
||||
## [1.6.5] - 2020-01-29
|
||||
### Changed
|
||||
- update version of go-scm
|
||||
- update alpine version in docker images
|
||||
- use ticker for cron jobs for more accurate timing
|
||||
|
||||
## [1.6.4] - 2019-12-30
|
||||
### Added
|
||||
- optionally enable pprof endpoints for profiling, by [@bradrydzewski](https://github.com/bradrydzewski).
|
||||
|
||||
## [1.6.3] - 2019-12-10
|
||||
### Fixed
|
||||
- disable caching generated yaml files by commit sha, by [@bradrydzewski](https://github.com/bradrydzewski).
|
||||
|
||||
### Added
|
||||
- support for bitbucket skipverify, by [@toni-moreno](https://github.com/toni-moreno).
|
||||
- support for gitea skipverify, by [@toni-moreno](https://github.com/toni-moreno).
|
||||
|
||||
## [1.6.2] - 2019-11-08
|
||||
### Added
|
||||
- support for loading license contents from env, by [@bradrydzewski](https://github.com/bradrydzewski).
|
||||
|
||||
### Fixed
|
||||
- regression not converting legacy pipeline when using new runners, by [@bradrydzewski](https://github.com/bradrydzewski).
|
||||
|
||||
## [1.6.1] - 2019-10-17
|
||||
### Added
|
||||
- updated autocert library in support of acme v2 protocol, by [@bradrydzewski](https://github.com/bradrydzewski).
|
||||
|
||||
### Fixed
|
||||
- fixed nil pointer when manually adding user from api, by [@bradrydzewski](https://github.com/bradrydzewski).
|
||||
|
||||
## [1.6.0] - 2019-10-04
|
||||
### Added
|
||||
- added nsswitch to docker images
|
||||
- option to auto-cancel pending builds when newer build enqueued, by [@bradrydzewski](https://github.com/bradrydzewski). [#1980](https://github.com/drone/drone/issues/1980).
|
||||
- endpoint to list all repositories in the database, by [@bradrydzewski](https://github.com/bradrydzewski). [#2785](https://github.com/drone/drone/issues/2785).
|
||||
|
||||
### Fixed
|
||||
- improve sync to handle duplicate repository names with different unique identifiers, by [@bradrydzewski](https://github.com/bradrydzewski). [#2658](https://github.com/drone/drone/issues/2658). _You can revert to the previous sync logic with DRONE_DATABASE_LEGACY_BATCH=true_.
|
||||
|
||||
## [1.5.1] - 2019-09-30
|
||||
### Added
|
||||
- allow organization admins access to organization secret endpoints, by [@bradrydzewski](https://github.com/bradrydzewski). [#2838](https://github.com/drone/drone/issues/2838).
|
||||
|
||||
### Fixed
|
||||
- fix invalid deep links in UI for github enterprise, by [@bradrydzewski](https://github.com/bradrydzewski).
|
||||
- ensure correct casing when manually adding user, by [@bradrydzewski](https://github.com/bradrydzewski). [#2766](https://github.com/drone/drone/issues/2766).
|
||||
|
||||
## [1.5.0] - 2019-09-28
|
||||
### Added
|
||||
- endpoint to execute a cron pipeline on-demand, by [@bradrydzewski](https://github.com/bradrydzewski). [#2781](https://github.com/drone/drone/issues/2781).
|
||||
- endpoint to list builds by branch, by [@bradrydzewski](https://github.com/bradrydzewski). [#1495](https://github.com/drone/drone/issues/1495).
|
||||
- ignore skip comments when cron event, by [@bradrydzewski](https://github.com/bradrydzewski). [#2835](https://github.com/drone/drone/issues/2835).
|
||||
- support for admission extensions, by [@bradrydzewski](https://github.com/bradrydzewski). [#2043](https://github.com/drone/drone/issues/2043).
|
||||
- endpoint to provide link to git resources, by [@bradrydzewski](https://github.com/bradrydzewski). [#2843](https://github.com/drone/drone/issues/2843).
|
||||
- improve bitbucket status display text on new pull request screen, by [@bradrydzewski](https://github.com/bradrydzewski).
|
||||
|
||||
### Fixed
|
||||
- missing cron job name in user interface, by [@bradrydzewski](https://github.com/bradrydzewski).
|
||||
- log lines not properly wrapping in user interface, by [@bradrydzewski](https://github.com/bradrydzewski).
|
||||
[#309](https://github.com/drone/drone-ui/issues/309).
|
||||
|
||||
### Breaking
|
||||
- the server now runs in multi-machine mode by default. In order to run the server in single-machine mode (agents disabled) you must set DRONE_AGENTS_DISABLED=true.
|
||||
|
||||
## [1.4.0] - 2019-09-12
|
||||
### Added
|
||||
- upgrade to Go 1.13 to resolve arm segfault, by [@KN4CK3R](https://github.com/KN4CK3R). [#2823](https://github.com/drone/drone/issues/2823).
|
||||
- configure default visibility, by [@JordanSussman](https://github.com/JordanSussman). [#2824](https://github.com/drone/drone/issues/2824).
|
||||
- configure default trusted flag, by [@vyckou](https://github.com/vyckou).
|
||||
- support for validation plugins, by [@bradrydzewski](https://github.com/bradrydzewski). [#2266](https://github.com/drone/drone/issues/2266).
|
||||
- support for conversion plugins, by [@bradrydzewski](https://github.com/bradrydzewski).
|
||||
- support for cron event type, by [@bradrydzewski](https://github.com/bradrydzewski). [#2705](https://github.com/drone/drone/issues/2705).
|
||||
- support for rollback event, by [@bradrydzewski](https://github.com/bradrydzewski). [#2695](https://github.com/drone/drone/issues/2695).
|
||||
- support for lets encrypt email, by [@bradrydzewski](https://github.com/bradrydzewski). [#2505](https://github.com/drone/drone/issues/2505).
|
||||
|
||||
### Removed
|
||||
- Support for basic auth as an option for Gitea, by [@techknowlogick](https://giteahub.com/techknowlogick). [#2721](https://github.com/drone/drone/issues/2721)
|
||||
|
||||
### Fixed
|
||||
- copy cron job name when restarting a cron job, by [@bradrydzewski](https://github.com/bradrydzewski). [#2760](https://github.com/drone/drone/issues/2760).
|
||||
|
||||
## [1.3.1] - 2019-08-26
|
||||
### Added
|
||||
- support for the GitHub deployment status API, by [@bradrydzewski](https://github.com/bradrydzewski).
|
||||
|
||||
## [1.3.0] - 2019-08-20
|
||||
### Added
|
||||
- support for storing logs in Azure Cloud Storage, by [@Lucretius](https://github.com/Lucretius). [#2788](https://github.com/drone/drone/pull/2788)
|
||||
- support for windows server 1903, by [@bradrydzewski](https://github.com/bradrydzewski).
|
||||
- button to view the full log file, by [@dramich](https://github.com/dramich). [drone/drone-ui#287](https://github.com/drone/drone-ui/pull/287).
|
||||
|
||||
### Fixed
|
||||
- read gogs sha from webhook, by [@marcotuna](https://github.com/marcotuna).
|
||||
- create bind volume on host if not exists, by [@bradrydzewski](https://github.com/bradrydzewski). [#2725](https://github.com/drone/drone/issues/2725).
|
||||
- preserve whitespace in build logs, by [@geek1011](https://github.com/geek1011). [drone/drone-ui#294](https://github.com/drone/drone-ui/pull/294).
|
||||
- enable log file download on firefox, by [@bobmanary](https://github.com/bobmanary). [drone/drone-ui#303](https://github.com/drone/drone-ui/pull/303)
|
||||
|
||||
### Security
|
||||
- upgraded to Go 1.12.9 due to CVE-2019-9512 and CVE-2019-9514
|
||||
|
||||
## [1.2.3] - 2019-07-30
|
||||
### Added
|
||||
|
||||
- disable github status for cron jobs
|
||||
- support for action in conditionals, by [@bradrydzewski](https://github.com/bradrydzewski). [#2685](https://github.com/drone/drone/issues/2685).
|
||||
|
||||
### Fixed
|
||||
|
||||
- improve cancel logic for dangling stages, by [@bradrydzewski](https://github.com/bradrydzewski).
|
||||
- improve error when kubernetes malforms the port configuration, by [@bradrydzewski](https://github.com/bradrydzewski). [#2742](https://github.com/drone/drone/issues/2742).
|
||||
- copy parameters from parent build when promoting, by [@bradrydzewski](https://github.com/bradrydzewski). [#2748](https://github.com/drone/drone/issues/2748).
|
||||
|
||||
## [1.2.2] - 2019-07-29
|
||||
### Added
|
||||
|
||||
- support for legacy environment variables
|
||||
- support for legacy workspace based on repository name
|
||||
- support for github deployment hooks
|
||||
- provide base sha for github pull requests
|
||||
- option to filter webhooks by event and type
|
||||
- upgrade drone-yaml to v1.2.2
|
||||
- upgrade drone-runtime to v1.0.7
|
||||
|
||||
### Fixed
|
||||
|
||||
- error when manually creating an empty user, by [@bradrydzewski](https://github.com/bradrydzewski). [#2738](https://github.com/drone/drone/issues/2738).
|
||||
|
||||
## [1.2.1] - 2019-06-11
|
||||
### Added
|
||||
|
||||
- support for legacy tokens to ease upgrade path, by [@bradrydzewski](https://github.com/bradrydzewski). [#2713](https://github.com/drone/drone/issues/2713).
|
||||
- include repository name and id in batch update error message, by [@bradrydzewski](https://github.com/bradrydzewski).
|
||||
|
||||
### Fixed
|
||||
|
||||
- fix inconsistent base64 encoding and decoding of encrypted secrets, by [@bradrydzewski](https://github.com/bradrydzewski).
|
||||
- update drone-yaml to version 1.1.2 for improved 0.8 to 1.0 yaml marshal escaping.
|
||||
- update drone-yaml to version 1.1.3 for improved 0.8 to 1.0 workspace conversion.
|
||||
|
||||
## [1.2.0] - 2019-05-30
|
||||
### Added
|
||||
|
||||
- endpoint to trigger new build for default branch, by [@bradrydzewski](https://github.com/bradrydzewski). [#2679](https://github.com/drone/drone/issues/2679).
|
||||
- endpoint to trigger new build for branch, by [@bradrydzewski](https://github.com/bradrydzewski). [#2679](https://github.com/drone/drone/issues/2679).
|
||||
- endpoint to trigger new build for branch and sha, by [@bradrydzewski](https://github.com/bradrydzewski). [#2679](https://github.com/drone/drone/issues/2679).
|
||||
- enable optional prometheus metrics guest access, by [@janberktold](https://github.com/janberktold)
|
||||
- fallback to database when logs not found in s3, by [@bradrydzewski](https://github.com/bradrydzewski). [#2689](https://github.com/drone/drone/issues/2689).
|
||||
- support for custom stage definitions and runners, by [@bradrydzewski](https://github.com/bradrydzewski). [#2680](https://github.com/drone/drone/issues/2680).
|
||||
- update drone-yaml to version 1.1.0
|
||||
|
||||
### Fixed
|
||||
|
||||
- retrieve latest build by branch, by [@tboerger](https://github.com/tboerger).
|
||||
- copy the fork value when restarting a build, by [@bradrydzewski](https://github.com/bradrydzewski). [#2708](https://github.com/drone/drone/issues/2708).
|
||||
- make healthz available without redirect, by [@bradrydzewski](https://github.com/bradrydzewski). [#2706](https://github.com/drone/drone/issues/2706).
|
||||
|
||||
## [1.1.0] - 2019-04-23
|
||||
### Added
|
||||
|
||||
- specify a user for the pipeline step, by [@bradrydzewski](https://github.com/bradrydzewski). [#2651](https://github.com/drone/drone/issues/2651).
|
||||
- support for Gitea oauth2, by [@techknowlogick](https://github.com/techknowlogick). [#2622](https://github.com/drone/drone/pull/2622).
|
||||
- ping the docker daemon before starting the agent, by [@bradrydzewski](https://github.com/bradrydzewski). [#2495](https://github.com/drone/drone/issues/2495).
|
||||
- support for Cron job name in Yaml trigger block, by [@bradrydzewski](https://github.com/bradrydzewski). [#2628](https://github.com/drone/drone/issues/2628).
|
||||
- support for Cron job name in Yaml when block, by [@bradrydzewski](https://github.com/bradrydzewski). [#2628](https://github.com/drone/drone/issues/2628).
|
||||
- sqlite username column changed to case-insensitive, by [@bradrydzewski](https://github.com/bradrydzewski).
|
||||
- endpoint to purge repository from database, by [@bradrydzewski](https://github.com/bradrydzewski).
|
||||
- support for per-organization secrets, by [@bradrydzewski](https://github.com/bradrydzewski).
|
||||
- include system metadata in global webhooks, by [@bradrydzewski](https://github.com/bradrydzewski).
|
||||
- ability to customize cookie secure flag, by [@bradrydzewski](https://github.com/bradrydzewski).
|
||||
- update drone-yaml from version 1.0.6 to 1.0.8.
|
||||
- update drone-runtime from version 1.0.4 to 1.0.6.
|
||||
- update go-scm from version 1.0.3 to 1.0.4.
|
||||
|
||||
### Fixed
|
||||
|
||||
- fixed error in mysql table creation syntax, from [@xuyang2](https://github.com/xuyang2). [#2677](https://github.com/drone/drone/pull/2677).
|
||||
- fixed stuck builds when upstream dependency is skipped, from [@bradrydzewski](https://github.com/bradrydzewski). [#2634](https://github.com/drone/drone/issues/2634).
|
||||
- fixed issue running steps with dependencies on failure, from [@bradrydzewski](https://github.com/bradrydzewski). [#2667](https://github.com/drone/drone/issues/2667).
|
||||
|
||||
## [1.0.1] - 2019-04-10
|
||||
### Added
|
||||
|
||||
- pass stage environment variables to pipeline steps, by [@bradrydzewski](https://github.com/bradrydzewski).
|
||||
- update go-scm to version 1.3.0, by [@bradrydzewski](https://github.com/bradrydzewski).
|
||||
- update drone-runtime to version to 1.0.4, by [@bradrydzewski](https://github.com/bradrydzewski).
|
||||
- ping docker daemon before agent starts to ensure connectivity, by [@bradrydzewski](https://github.com/bradrydzewski).
|
||||
238
LICENSE
238
LICENSE
|
|
@ -1,201 +1,89 @@
|
|||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
Copyright 2019 Drone.IO, Inc.
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
The Drone Community Edition is licensed under the Apache License,
|
||||
Version 2.0 (the "Apache License"). You may obtain a copy of the
|
||||
Apache License at
|
||||
|
||||
1. Definitions.
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
The Drone Enterprise Edition is licensed under the Drone
|
||||
Non-Commercial License (the "Non-Commercial License"). A copy of
|
||||
the Non-Commercial License is provided below.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
The source files in this repository have a header indicating
|
||||
which license they are under. The BUILDING_OSS file provides
|
||||
instructions for creating the Community Edition distribution
|
||||
subject to the terms of the Apache License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
-----------------------------------------------------------------
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
Drone Non-Commercial License
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
Contributor: Drone.IO, Inc.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
Source Code: https://github.com/harness/drone
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
This license lets you use and share this software for free,
|
||||
with a trial-length time limit on commercial use. Specifically:
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
If you follow the rules below, you may do everything with this
|
||||
software that would otherwise infringe either the contributor's
|
||||
copyright in it, any patent claim the contributor can license
|
||||
that covers this software as of the contributor's latest
|
||||
contribution, or both.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
1. You must limit use of this software in any manner primarily
|
||||
intended for or directed toward commercial advantage or
|
||||
private monetary compensation to a trial period of 32
|
||||
consecutive calendar days. This limit does not apply to use in
|
||||
developing feedback, modifications, or extensions that you
|
||||
contribute back to those giving this license.
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
2. Ensure everyone who gets a copy of this software from you, in
|
||||
source code or any other form, gets the text of this license
|
||||
and the contributor and source code lines above.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
3. Do not make any legal claim against anyone for infringing any
|
||||
patent claim they would infringe by using this software alone,
|
||||
accusing this software, with or without changes, alone or as
|
||||
part of a larger application.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
You are excused for unknowingly breaking rule 1 if you stop
|
||||
doing anything requiring this license within 30 days of
|
||||
learning you broke the rule.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
**This software comes as is, without any warranty at all. As far
|
||||
as the law allows, the contributor will not be liable for any
|
||||
damages related to this software or this license, for any kind of
|
||||
legal claim.**
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
-----------------------------------------------------------------
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
Waiver: Individual and Small Business
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
Contributor waives the terms of rule 1 for companies meeting all
|
||||
the following criteria, counting all subsidiaries and affiliated
|
||||
entities as one:
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
1. worldwide annual gross revenue under $5 million US dollars,
|
||||
per generally accepted accounting principles
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
2. less than $5 million US dollars in all-time aggregate debt and
|
||||
equity financing
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
Contributor will not revoke this waiver, but may change terms for
|
||||
future versions of the software.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
-----------------------------------------------------------------
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
Waiver: Low Usage
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
Contributor waives the terms of rule 1 for companies meeting all
|
||||
the following criteria, counting all subsidiaries and affiliated
|
||||
entities as one:
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
1. less than 5,000 total pipelines executed using this software
|
||||
in the immediately preceding, year-long period
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "{}"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright 2023 Harness, Inc.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
Contributor will not revoke this waiver, but may change terms for
|
||||
future versions of the software.
|
||||
|
|
|
|||
205
Makefile
205
Makefile
|
|
@ -1,205 +0,0 @@
|
|||
ifndef GOPATH
|
||||
GOPATH := $(shell go env GOPATH)
|
||||
endif
|
||||
ifndef GOBIN # derive value from gopath (default to first entry, similar to 'go get')
|
||||
GOBIN := $(shell go env GOPATH | sed 's/:.*//')/bin
|
||||
endif
|
||||
|
||||
tools = $(addprefix $(GOBIN)/, golangci-lint goimports govulncheck protoc-gen-go protoc-gen-go-grpc gci)
|
||||
deps = $(addprefix $(GOBIN)/, wire dbmate)
|
||||
|
||||
ifneq (,$(wildcard ./.local.env))
|
||||
include ./.local.env
|
||||
export
|
||||
endif
|
||||
|
||||
.DEFAULT_GOAL := all
|
||||
|
||||
###############################################################################
|
||||
#
|
||||
# Initialization
|
||||
#
|
||||
###############################################################################
|
||||
|
||||
init: ## Install git hooks to perform pre-commit checks
|
||||
git config core.hooksPath .githooks
|
||||
git config commit.template .gitmessage
|
||||
|
||||
dep: $(deps) ## Install the deps required to generate code and build Harness
|
||||
@echo "Installing dependencies"
|
||||
@go mod download
|
||||
|
||||
tools: $(tools) ## Install tools required for the build
|
||||
@echo "Installed tools"
|
||||
|
||||
###############################################################################
|
||||
#
|
||||
# Harness Build and testing rules
|
||||
#
|
||||
###############################################################################
|
||||
|
||||
web-build: ## Build the web frontend
|
||||
@echo "Building web frontend"
|
||||
@cd web && yarn install && yarn build
|
||||
|
||||
build: generate ## Build the all-in-one Harness binary
|
||||
@echo "Building Harness Server"
|
||||
go build -o ./gitness ./cmd/gitness
|
||||
|
||||
test: generate ## Run the go tests
|
||||
@echo "Running tests"
|
||||
@go test -v -coverprofile=coverage.out `go list ./... | egrep -v "./registry/tests/(maven|cargo|gopkg|npm)"`
|
||||
@go tool cover -html=coverage.out
|
||||
|
||||
|
||||
|
||||
###############################################################################
|
||||
#
|
||||
# Artifact Registry Build and testing rules
|
||||
#
|
||||
###############################################################################
|
||||
|
||||
run: ar-clean build
|
||||
./gitness server .local.env || true
|
||||
|
||||
# Main conformance test targets
|
||||
ar-conformance-test: ar-clean build
|
||||
./gitness server .local.env > logfile.log 2>&1 & echo $$! > server.PID
|
||||
sleep 20
|
||||
./registry/tests/conformance_test.sh localhost:3000
|
||||
@EXIT_CODE=$$?;
|
||||
@kill `cat server.PID` 2>/dev/null || true
|
||||
@rm -f server.PID
|
||||
@rm -f logfile.log
|
||||
@exit $$EXIT_CODE
|
||||
|
||||
ar-hot-conformance-test:
|
||||
@echo "Running OCI conformance tests..."
|
||||
rm -rf distribution-spec || true
|
||||
./registry/tests/conformance_test.sh localhost:3000 || true
|
||||
@echo "Running Maven conformance tests..."
|
||||
./registry/tests/maven/scripts/setup_test.sh localhost:3000
|
||||
@chmod +x /tmp/maven_env.sh
|
||||
source /tmp/maven_env.sh && go test -v ./registry/tests/maven/... -ginkgo.v || true
|
||||
@echo "Running Cargo conformance tests..."
|
||||
./registry/tests/cargo/scripts/setup_test.sh localhost:3000
|
||||
@chmod +x /tmp/cargo_env.sh
|
||||
source /tmp/cargo_env.sh && go test -v ./registry/tests/cargo/... -ginkgo.v || true
|
||||
@chmod +x /tmp/go_env.sh
|
||||
source /tmp/go_env.sh && go test -v ./registry/tests/gopkg/... -ginkgo.v || true
|
||||
@echo "Running NPM conformance tests..."
|
||||
./registry/tests/npm/scripts/setup_test.sh localhost:3000
|
||||
@chmod +x /tmp/npm_env.sh
|
||||
source /tmp/npm_env.sh && go test -v ./registry/tests/npm/... -ginkgo.v || true
|
||||
|
||||
ar-api-update:
|
||||
@set -e; \
|
||||
oapi-codegen --config ./registry/config/openapi/artifact-services.yaml ./registry/app/api/openapi/api.yaml; \
|
||||
oapi-codegen --config ./registry/config/openapi/artifact-types.yaml ./registry/app/api/openapi/api.yaml;
|
||||
|
||||
ar-clean:
|
||||
@rm artifact-registry 2> /dev/null || true
|
||||
@docker stop ps_artifacthub 2> /dev/null || true
|
||||
rm -rf distribution-spec
|
||||
@kill -9 $$(lsof -t -i:3000) || true
|
||||
@rm server.PID || true
|
||||
@rm logfile.log || true
|
||||
go clean
|
||||
|
||||
###############################################################################
|
||||
#
|
||||
# Code Formatting and linting
|
||||
#
|
||||
###############################################################################
|
||||
|
||||
format: tools # Format go code and error if any changes are made
|
||||
@echo "Formatting ..."
|
||||
@goimports -w .
|
||||
@gci write --skip-generated --custom-order -s standard -s "prefix(github.com/harness/gitness)" -s default -s blank -s dot .
|
||||
@echo "Formatting complete"
|
||||
|
||||
modernize:
|
||||
@echo "Modernizing ..."
|
||||
@go run golang.org/x/tools/gopls/internal/analysis/modernize/cmd/modernize@latest -fix -test ./...
|
||||
|
||||
sec:
|
||||
@echo "Vulnerability detection $(1)"
|
||||
@govulncheck ./...
|
||||
|
||||
lint: tools generate # lint the golang code - CI
|
||||
@echo "Linting $(1)"
|
||||
@golangci-lint run --timeout=5m --verbose --new-from-rev=HEAD~ --whole-files
|
||||
|
||||
lint-full: tools generate # full linting the golang code
|
||||
@echo "Linting $(1)"
|
||||
@golangci-lint run --timeout=5m --verbose
|
||||
|
||||
lint-local: tools generate # lint the golang code - only untracked and staged changes
|
||||
@echo "Linting $(1)"
|
||||
@golangci-lint run --new-from-merge-base=main --new --timeout=5m --verbose --whole-files
|
||||
|
||||
|
||||
###############################################################################
|
||||
# Code Generation
|
||||
#
|
||||
# Some code generation can be slow, so we only run it if
|
||||
# the source file has changed.
|
||||
###############################################################################
|
||||
|
||||
generate: wire
|
||||
@echo "Generated Code"
|
||||
|
||||
wire: cmd/gitness/wire_gen.go
|
||||
|
||||
force-wire: ## Force wire code generation
|
||||
@sh ./scripts/wire/gitness.sh
|
||||
|
||||
cmd/gitness/wire_gen.go: cmd/gitness/wire.go
|
||||
@sh ./scripts/wire/gitness.sh
|
||||
|
||||
###############################################################################
|
||||
# Install Tools and deps
|
||||
#
|
||||
# These targets specify the full path to where the tool is installed
|
||||
# If the tool already exists it wont be re-installed.
|
||||
###############################################################################
|
||||
|
||||
update-tools: delete-tools $(tools) ## Update the tools by deleting and re-installing
|
||||
|
||||
delete-tools: ## Delete the tools
|
||||
@rm $(tools) || true
|
||||
|
||||
# Install golangci-lint
|
||||
$(GOBIN)/golangci-lint:
|
||||
@echo "🔘 Installing golangci-lint... (`date '+%H:%M:%S'`)"
|
||||
@curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(GOBIN) v2.4.0
|
||||
|
||||
# Install goimports to format code
|
||||
$(GOBIN)/goimports:
|
||||
@echo "🔘 Installing goimports ... (`date '+%H:%M:%S'`)"
|
||||
@go install golang.org/x/tools/cmd/goimports
|
||||
|
||||
# Install wire to generate dependency injection
|
||||
$(GOBIN)/wire:
|
||||
go install github.com/google/wire/cmd/wire@latest
|
||||
|
||||
# Install dbmate to perform db migrations
|
||||
$(GOBIN)/dbmate:
|
||||
go install github.com/amacneil/dbmate@v1.15.0
|
||||
|
||||
$(GOBIN)/govulncheck:
|
||||
go install golang.org/x/vuln/cmd/govulncheck@v1.1.4
|
||||
|
||||
$(GOBIN)/protoc-gen-go:
|
||||
go install google.golang.org/protobuf/cmd/protoc-gen-go@v1.28
|
||||
|
||||
$(GOBIN)/protoc-gen-go-grpc:
|
||||
go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@v1.2
|
||||
|
||||
$(GOBIN)/gci:
|
||||
go install github.com/daixiang0/gci@v0.13.7
|
||||
|
||||
help: ## show help message
|
||||
@awk 'BEGIN {FS = ":.*##"; printf "\nUsage:\n make \033[36m\033[0m\n"} /^[$$()% 0-9a-zA-Z_-]+:.*?##/ { printf " \033[36m%-15s\033[0m %s\n", $$1, $$2 } /^##@/ { printf "\n\033[1m%s\033[0m\n", substr($$0, 5) } ' $(MAKEFILE_LIST)
|
||||
|
||||
.PHONY: delete-tools update-tools help format lint
|
||||
18
NOTICE
18
NOTICE
|
|
@ -1,12 +1,14 @@
|
|||
Copyright 2024 Harness, Inc.
|
||||
Drone
|
||||
Copyright 2019 Drone.IO, Inc
|
||||
|
||||
This product includes software developed at
|
||||
This product includes software developed at Drone.IO, Inc.
|
||||
(http://drone.io/).
|
||||
|
||||
https://github.com/goharbor/harbor
|
||||
Licensed under the Apache License, Version 2.0
|
||||
This product includes software developed by Docker, Inc.
|
||||
(https://www.docker.com/).
|
||||
|
||||
https://github.com/distribution/distribution
|
||||
Licensed under the Apache License, Version 2.0
|
||||
This product includes software developed by Canonical Ltd.
|
||||
(https://www.canonical.com/).
|
||||
|
||||
https://gitlab.com/gitlab-org/container-registry
|
||||
Licensed under the Apache License, Version 2.0
|
||||
This product includes software developed at CoreOS, Inc.
|
||||
(http://www.coreos.com/).
|
||||
|
|
|
|||
152
README.md
152
README.md
|
|
@ -1,152 +0,0 @@
|
|||
# Harness
|
||||
Harness Open Source is an open source development platform packed with the power of code hosting, automated DevOps pipelines, hosted development environments (Gitspaces), and artifact registries.
|
||||
|
||||
## Overview
|
||||
Harness Open source is an open source development platform packed with the power of code hosting, automated DevOps pipelines, Gitspaces, and artifact registries.
|
||||
|
||||
|
||||
## Running Harness locally
|
||||
> The latest publicly released docker image can be found on [harness/harness](https://hub.docker.com/r/harness/harness).
|
||||
|
||||
To install Harness yourself, simply run the command below. Once the container is up, you can visit http://localhost:3000 in your browser.
|
||||
|
||||
```bash
|
||||
docker run -d \
|
||||
-p 3000:3000 \
|
||||
-p 3022:3022 \
|
||||
-v /var/run/docker.sock:/var/run/docker.sock \
|
||||
-v /tmp/harness:/data \
|
||||
--name harness \
|
||||
--restart always \
|
||||
harness/harness
|
||||
```
|
||||
> The Harness image uses a volume to store the database and repositories. It is highly recommended to use a bind mount or named volume as otherwise all data will be lost once the container is stopped.
|
||||
|
||||
See [developer.harness.io](https://developer.harness.io/docs/open-source) to learn how to get the most out of Harness.
|
||||
|
||||
## Where is Drone?
|
||||
|
||||
Harness Open Source represents a massive investment in the next generation of Drone. Where Drone focused solely on continuous integration, Harness adds source code hosting, developer environments (gitspaces), and artifact registries; providing teams with an end-to-end, open source DevOps platform.
|
||||
|
||||
The goal is for Harness to eventually be at full parity with Drone in terms of pipeline capabilities, allowing users to seamlessly migrate from Drone to Harness.
|
||||
|
||||
But, we expect this to take some time, which is why we took a snapshot of Drone as a feature branch [drone](https://github.com/harness/harness/tree/drone) ([README](https://github.com/harness/harness/blob/drone/.github/readme.md)) so it can continue development.
|
||||
|
||||
As for Harness, the development is taking place on the [main](https://github.com/harness/harness/tree/main) branch.
|
||||
|
||||
For more information on Harness, please visit [developer.harness.io](https://developer.harness.io/).
|
||||
|
||||
For more information on Drone, please visit [drone.io](https://www.drone.io/).
|
||||
|
||||
## Harness Open Source Development
|
||||
### Pre-Requisites
|
||||
|
||||
Install the latest stable version of Node and Go version 1.20 or higher, and then install the below Go programs. Ensure the GOPATH [bin directory](https://go.dev/doc/gopath_code#GOPATH) is added to your PATH.
|
||||
|
||||
Install protobuf
|
||||
- Check if you've already installed protobuf ```protoc --version```
|
||||
- If your version is different than v3.21.11, run ```brew unlink protobuf```
|
||||
- Get v3.21.11 ```curl -s https://raw.githubusercontent.com/Homebrew/homebrew-core/9de8de7a533609ebfded833480c1f7c05a3448cb/Formula/protobuf.rb > /tmp/protobuf.rb```
|
||||
- Install it ```brew install /tmp/protobuf.rb```
|
||||
- Check out your version ```protoc --version```
|
||||
|
||||
Install protoc-gen-go and protoc-gen-go-rpc:
|
||||
|
||||
- Install protoc-gen-go v1.28.1 ```go install google.golang.org/protobuf/cmd/protoc-gen-go@v1.28.1```
|
||||
(Note that this will install a binary in $GOBIN so make sure $GOBIN is in your $PATH)
|
||||
|
||||
- Install protoc-gen-go-grpc v1.2.0 ```go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@v1.2.0```
|
||||
|
||||
```bash
|
||||
$ make dep
|
||||
$ make tools
|
||||
```
|
||||
|
||||
### Build
|
||||
|
||||
First step is to build the user interface artifacts:
|
||||
|
||||
```bash
|
||||
$ pushd web
|
||||
$ yarn install
|
||||
$ yarn build
|
||||
$ popd
|
||||
```
|
||||
|
||||
After that, you can build the Harness binary:
|
||||
|
||||
```bash
|
||||
$ make build
|
||||
```
|
||||
|
||||
### Run
|
||||
|
||||
This project supports all operating systems and architectures supported by Go. This means you can build and run the system on your machine; docker containers are not required for local development and testing.
|
||||
|
||||
To start the server at `localhost:3000`, simply run the following command:
|
||||
|
||||
```bash
|
||||
./gitness server .local.env
|
||||
```
|
||||
|
||||
### Auto-Generate Harness API Client used by UI using Swagger
|
||||
Please make sure to update the autogenerated client code used by the UI when adding new rest APIs.
|
||||
|
||||
To regenerate the code, please execute the following steps:
|
||||
- Regenerate swagger with latest Harness binary `./gitness swagger > web/src/services/code/swagger.yaml`
|
||||
- navigate to the `web` folder and run `yarn services`
|
||||
|
||||
The latest API changes should now be reflected in `web/src/services/code/index.tsx`
|
||||
|
||||
# Run Registry Conformance Tests
|
||||
```
|
||||
make conformance-test
|
||||
```
|
||||
For running conformance tests with existing running service, use:
|
||||
```
|
||||
make hot-conformance-test
|
||||
```
|
||||
|
||||
## User Interface
|
||||
|
||||
This project includes a full user interface for interacting with the system. When you run the application, you can access the user interface by navigating to `http://localhost:3000` in your browser.
|
||||
|
||||
## REST API
|
||||
|
||||
This project includes a swagger specification. When you run the application, you can access the swagger specification by navigating to `http://localhost:3000/swagger` in your browser (for raw yaml see `http://localhost:3000/openapi.yaml`).
|
||||
For registry endpoints, currently swagger is located on different endpoint `http://localhost:3000/registry/swagger/` (for raw json see `http://localhost:3000/registry/swagger.json`). These will be later moved to the main swagger endpoint.
|
||||
|
||||
|
||||
For testing, it's simplest to just use the cli to create a token (this requires Harness server to run):
|
||||
```bash
|
||||
# LOGIN (user: admin, pw: changeit)
|
||||
$ ./gitness login
|
||||
|
||||
# GENERATE PAT (1 YEAR VALIDITY)
|
||||
$ ./gitness user pat "my-pat-uid" 2592000
|
||||
```
|
||||
|
||||
The command outputs a valid PAT that has been granted full access as the user.
|
||||
The token can then be send as part of the `Authorization` header with Postman or curl:
|
||||
|
||||
```bash
|
||||
$ curl http://localhost:3000/api/v1/user \
|
||||
-H "Authorization: Bearer $TOKEN"
|
||||
```
|
||||
|
||||
|
||||
## CLI
|
||||
This project includes VERY basic command line tools for development and running the service. Please remember that you must start the server before you can execute commands.
|
||||
|
||||
For a full list of supported operations, please see
|
||||
```bash
|
||||
$ ./gitness --help
|
||||
```
|
||||
|
||||
## Contributing
|
||||
|
||||
Refer to [CONTRIBUTING.md](https://github.com/harness/harness/blob/main/CONTRIBUTING.md)
|
||||
|
||||
## License
|
||||
|
||||
Apache License 2.0, see [LICENSE](https://github.com/harness/harness/blob/main/LICENSE).
|
||||
|
|
@ -0,0 +1,129 @@
|
|||
# https://taskfile.org
|
||||
|
||||
version: '2'
|
||||
|
||||
tasks:
|
||||
install:
|
||||
dir: cmd/drone-server
|
||||
cmds: [ go install -v ]
|
||||
env:
|
||||
GO111MODULE: on
|
||||
|
||||
build:
|
||||
cmds:
|
||||
- task: build-base
|
||||
vars: { name: server }
|
||||
|
||||
build-base:
|
||||
env:
|
||||
GOOS: linux
|
||||
GOARCH: amd64
|
||||
CGO_ENABLED: '0'
|
||||
GO111MODULE: 'on'
|
||||
cmds:
|
||||
- cmd: >
|
||||
go build -o release/linux/amd64/drone-{{.name}}
|
||||
github.com/drone/drone/cmd/drone-{{.name}}
|
||||
|
||||
cleanup:
|
||||
cmds:
|
||||
- rm -rf release
|
||||
|
||||
docker:
|
||||
cmds:
|
||||
- task: docker-base
|
||||
vars: { name: server, image: drone/drone }
|
||||
|
||||
docker-base:
|
||||
vars:
|
||||
GIT_BRANCH:
|
||||
sh: git rev-parse --abbrev-ref HEAD
|
||||
cmds:
|
||||
- cmd: docker rmi {{.image}}
|
||||
ignore_error: true
|
||||
- cmd: docker rmi {{.image}}:{{.GIT_BRANCH}}
|
||||
ignore_error: true
|
||||
- cmd: >
|
||||
docker build --rm
|
||||
-f docker/Dockerfile.{{.name}}.linux.amd64
|
||||
-t {{.image}} .
|
||||
- cmd: >
|
||||
docker tag {{.image}} {{.image}}:{{.GIT_BRANCH}}
|
||||
|
||||
test:
|
||||
cmds:
|
||||
- go test ./...
|
||||
env:
|
||||
GO111MODULE: 'on'
|
||||
|
||||
test-mysql:
|
||||
env:
|
||||
DRONE_DATABASE_DRIVER: mysql
|
||||
DRONE_DATABASE_DATASOURCE: root@tcp(localhost:3306)/test?parseTime=true
|
||||
GO111MODULE: 'on'
|
||||
cmds:
|
||||
- cmd: docker kill mysql
|
||||
silent: true
|
||||
ignore_error: true
|
||||
- cmd: >
|
||||
docker run
|
||||
-p 3306:3306
|
||||
--env MYSQL_DATABASE=test
|
||||
--env MYSQL_ALLOW_EMPTY_PASSWORD=yes
|
||||
--name mysql
|
||||
--detach
|
||||
--rm
|
||||
mysql:5.7
|
||||
--character-set-server=utf8mb4
|
||||
--collation-server=utf8mb4_unicode_ci
|
||||
- cmd: go test -count=1 github.com/drone/drone/store/batch
|
||||
- cmd: go test -count=1 github.com/drone/drone/store/batch2
|
||||
- cmd: go test -count=1 github.com/drone/drone/store/build
|
||||
- cmd: go test -count=1 github.com/drone/drone/store/card
|
||||
- cmd: go test -count=1 github.com/drone/drone/store/cron
|
||||
- cmd: go test -count=1 github.com/drone/drone/store/logs
|
||||
- cmd: go test -count=1 github.com/drone/drone/store/perm
|
||||
- cmd: go test -count=1 github.com/drone/drone/store/repos
|
||||
- cmd: go test -count=1 github.com/drone/drone/store/secret
|
||||
- cmd: go test -count=1 github.com/drone/drone/store/secret/global
|
||||
- cmd: go test -count=1 github.com/drone/drone/store/stage
|
||||
- cmd: go test -count=1 github.com/drone/drone/store/step
|
||||
- cmd: go test -count=1 github.com/drone/drone/store/template
|
||||
- cmd: go test -count=1 github.com/drone/drone/store/user
|
||||
- cmd: docker kill mysql
|
||||
|
||||
test-postgres:
|
||||
env:
|
||||
DRONE_DATABASE_DRIVER: postgres
|
||||
DRONE_DATABASE_DATASOURCE: host=localhost user=postgres password=postgres dbname=postgres sslmode=disable
|
||||
GO111MODULE: 'on'
|
||||
cmds:
|
||||
- cmd: docker kill postgres
|
||||
ignore_error: true
|
||||
silent: false
|
||||
- silent: false
|
||||
cmd: >
|
||||
docker run
|
||||
-p 5432:5432
|
||||
--env POSTGRES_PASSWORD=postgres
|
||||
--env POSTGRES_USER=postgres
|
||||
--name postgres
|
||||
--detach
|
||||
--rm
|
||||
postgres:9-alpine
|
||||
- cmd: go test -count=1 github.com/drone/drone/store/batch
|
||||
- cmd: go test -count=1 github.com/drone/drone/store/batch2
|
||||
- cmd: go test -count=1 github.com/drone/drone/store/build
|
||||
- cmd: go test -count=1 github.com/drone/drone/store/card
|
||||
- cmd: go test -count=1 github.com/drone/drone/store/cron
|
||||
- cmd: go test -count=1 github.com/drone/drone/store/logs
|
||||
- cmd: go test -count=1 github.com/drone/drone/store/perm
|
||||
- cmd: go test -count=1 github.com/drone/drone/store/repos
|
||||
- cmd: go test -count=1 github.com/drone/drone/store/secret
|
||||
- cmd: go test -count=1 github.com/drone/drone/store/secret/global
|
||||
- cmd: go test -count=1 github.com/drone/drone/store/stage
|
||||
- cmd: go test -count=1 github.com/drone/drone/store/step
|
||||
- cmd: go test -count=1 github.com/drone/drone/store/template
|
||||
- cmd: go test -count=1 github.com/drone/drone/store/user
|
||||
- cmd: docker kill postgres
|
||||
silent: true
|
||||
|
|
@ -1,15 +0,0 @@
|
|||
// Copyright 2023 Harness, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package api
|
||||
|
|
@ -1,149 +0,0 @@
|
|||
// Copyright 2023 Harness, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package auth
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/harness/gitness/app/auth"
|
||||
"github.com/harness/gitness/app/auth/authz"
|
||||
"github.com/harness/gitness/app/paths"
|
||||
"github.com/harness/gitness/app/store"
|
||||
"github.com/harness/gitness/types"
|
||||
"github.com/harness/gitness/types/enum"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrUnauthorized = errors.New("unauthorized")
|
||||
ErrForbidden = errors.New("forbidden")
|
||||
ErrParentResourceTypeUnknown = errors.New("Unknown parent resource type")
|
||||
ErrPrincipalTypeUnknown = errors.New("Unknown principal type")
|
||||
)
|
||||
|
||||
// Check checks if a resource specific permission is granted for the current auth session in the scope.
|
||||
// Returns nil if the permission is granted, otherwise returns an error.
|
||||
func Check(
|
||||
ctx context.Context, authorizer authz.Authorizer, session *auth.Session,
|
||||
scope *types.Scope, resource *types.Resource, permission enum.Permission,
|
||||
) error {
|
||||
authenticated, err := authorizer.Check(
|
||||
ctx,
|
||||
session,
|
||||
scope,
|
||||
resource,
|
||||
permission,
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return CheckSessionAuth(session, authenticated)
|
||||
}
|
||||
|
||||
// CheckAll checks if multiple resources specific permission is granted for the current auth session in the scope.
|
||||
// Returns nil if the permission is granted, otherwise returns an error.
|
||||
func CheckAll(
|
||||
ctx context.Context, authorizer authz.Authorizer, session *auth.Session,
|
||||
permissionChecks ...types.PermissionCheck,
|
||||
) error {
|
||||
hasPermission, err := authorizer.CheckAll(
|
||||
ctx,
|
||||
session,
|
||||
permissionChecks...,
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return CheckSessionAuth(session, hasPermission)
|
||||
}
|
||||
|
||||
// CheckSessionAuth returns nil if the user is authenticated.
|
||||
// Otherwise, ir returns err unauthorized on anonymous or err forbidden on non anonymous session.
|
||||
func CheckSessionAuth(session *auth.Session, authenticated bool) error {
|
||||
if !authenticated {
|
||||
if auth.IsAnonymousSession(session) {
|
||||
return ErrUnauthorized
|
||||
}
|
||||
return ErrForbidden
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// IsNoAccess returns true if the error is ErrUnauthorized or ErrForbidden.
|
||||
func IsNoAccess(err error) bool {
|
||||
return errors.Is(err, ErrForbidden) || errors.Is(err, ErrUnauthorized)
|
||||
}
|
||||
|
||||
// CheckChild checks if a resource specific permission is granted for the current auth session
|
||||
// in the scope of a parent.
|
||||
// Returns nil if the permission is granted, otherwise returns an error.
|
||||
// NotAuthenticated, NotAuthorized, or any underlying error.
|
||||
func CheckChild(
|
||||
ctx context.Context, authorizer authz.Authorizer, session *auth.Session,
|
||||
spaceStore store.SpaceStore, repoStore store.RepoStore, parentType enum.ParentResourceType, parentID int64,
|
||||
resourceType enum.ResourceType, resourceName string, permission enum.Permission,
|
||||
) error {
|
||||
scope, err := getScopeForParent(ctx, spaceStore, repoStore, parentType, parentID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
resource := &types.Resource{
|
||||
Type: resourceType,
|
||||
Identifier: resourceName,
|
||||
}
|
||||
|
||||
return Check(ctx, authorizer, session, scope, resource, permission)
|
||||
}
|
||||
|
||||
// getScopeForParent Returns the scope for a given resource parent (space or repo).
|
||||
func getScopeForParent(
|
||||
ctx context.Context, spaceStore store.SpaceStore, repoStore store.RepoStore,
|
||||
parentType enum.ParentResourceType, parentID int64,
|
||||
) (*types.Scope, error) {
|
||||
// TODO: Can this be done cleaner?
|
||||
switch parentType {
|
||||
case enum.ParentResourceTypeSpace:
|
||||
space, err := spaceStore.Find(ctx, parentID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("parent space not found: %w", err)
|
||||
}
|
||||
|
||||
return &types.Scope{SpacePath: space.Path}, nil
|
||||
|
||||
case enum.ParentResourceTypeRepo:
|
||||
repo, err := repoStore.Find(ctx, parentID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("parent repo not found: %w", err)
|
||||
}
|
||||
|
||||
spacePath, repoName, err := paths.DisectLeaf(repo.Path)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to disect path '%s': %w", repo.Path, err)
|
||||
}
|
||||
|
||||
return &types.Scope{SpacePath: spacePath, Repo: repoName}, nil
|
||||
|
||||
default:
|
||||
log.Ctx(ctx).Debug().Msgf("Unsupported parent type encountered: '%s'", parentType)
|
||||
|
||||
return nil, ErrParentResourceTypeUnknown
|
||||
}
|
||||
}
|
||||
|
|
@ -1,45 +0,0 @@
|
|||
// Copyright 2023 Harness, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package auth
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/harness/gitness/app/auth"
|
||||
"github.com/harness/gitness/app/auth/authz"
|
||||
"github.com/harness/gitness/types"
|
||||
"github.com/harness/gitness/types/enum"
|
||||
)
|
||||
|
||||
// CheckConnector checks if a repo specific permission is granted for the current auth session
|
||||
// in the scope of its parent.
|
||||
// Returns nil if the permission is granted, otherwise returns an error.
|
||||
// NotAuthenticated, NotAuthorized, or any underlying error.
|
||||
func CheckConnector(
|
||||
ctx context.Context,
|
||||
authorizer authz.Authorizer,
|
||||
session *auth.Session,
|
||||
parentPath,
|
||||
identifier string,
|
||||
permission enum.Permission,
|
||||
) error {
|
||||
scope := &types.Scope{SpacePath: parentPath}
|
||||
resource := &types.Resource{
|
||||
Type: enum.ResourceTypeConnector,
|
||||
Identifier: identifier,
|
||||
}
|
||||
|
||||
return Check(ctx, authorizer, session, scope, resource, permission)
|
||||
}
|
||||
|
|
@ -1,45 +0,0 @@
|
|||
// Copyright 2023 Harness, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package auth
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/harness/gitness/app/auth"
|
||||
"github.com/harness/gitness/app/auth/authz"
|
||||
"github.com/harness/gitness/types"
|
||||
"github.com/harness/gitness/types/enum"
|
||||
)
|
||||
|
||||
// CheckGitspace checks if a gitspace specific permission is granted for the current auth session
|
||||
// in the scope of its parent.
|
||||
// Returns nil if the permission is granted, otherwise returns an error.
|
||||
// NotAuthenticated, NotAuthorized, or any underlying error.
|
||||
func CheckGitspace(
|
||||
ctx context.Context,
|
||||
authorizer authz.Authorizer,
|
||||
session *auth.Session,
|
||||
parentPath,
|
||||
identifier string,
|
||||
permission enum.Permission,
|
||||
) error {
|
||||
scope := &types.Scope{SpacePath: parentPath}
|
||||
resource := &types.Resource{
|
||||
Type: enum.ResourceTypeGitspace,
|
||||
Identifier: identifier,
|
||||
}
|
||||
|
||||
return Check(ctx, authorizer, session, scope, resource, permission)
|
||||
}
|
||||
|
|
@ -1,45 +0,0 @@
|
|||
// Copyright 2023 Harness, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package auth
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/harness/gitness/app/auth"
|
||||
"github.com/harness/gitness/app/auth/authz"
|
||||
"github.com/harness/gitness/types"
|
||||
"github.com/harness/gitness/types/enum"
|
||||
)
|
||||
|
||||
// CheckInfraProvider checks if a gitspace specific permission is granted for the current auth session
|
||||
// in the scope of its parent.
|
||||
// Returns nil if the permission is granted, otherwise returns an error.
|
||||
// NotAuthenticated, NotAuthorized, or any underlying error.
|
||||
func CheckInfraProvider(
|
||||
ctx context.Context,
|
||||
authorizer authz.Authorizer,
|
||||
session *auth.Session,
|
||||
parentPath,
|
||||
identifier string,
|
||||
permission enum.Permission,
|
||||
) error {
|
||||
scope := &types.Scope{SpacePath: parentPath}
|
||||
resource := &types.Resource{
|
||||
Type: enum.ResourceTypeInfraProvider,
|
||||
Identifier: identifier,
|
||||
}
|
||||
|
||||
return Check(ctx, authorizer, session, scope, resource, permission)
|
||||
}
|
||||
|
|
@ -1,44 +0,0 @@
|
|||
// Copyright 2023 Harness, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package auth
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/harness/gitness/app/auth"
|
||||
"github.com/harness/gitness/app/auth/authz"
|
||||
"github.com/harness/gitness/app/paths"
|
||||
"github.com/harness/gitness/types"
|
||||
"github.com/harness/gitness/types/enum"
|
||||
)
|
||||
|
||||
// CheckPipeline checks if a pipeline specific permission is granted for the current auth session
|
||||
// in the scope of the parent.
|
||||
// Returns nil if the permission is granted, otherwise returns an error.
|
||||
// NotAuthenticated, NotAuthorized, or any underlying error.
|
||||
func CheckPipeline(ctx context.Context, authorizer authz.Authorizer, session *auth.Session,
|
||||
repoPath string, pipelineIdentifier string, permission enum.Permission) error {
|
||||
spacePath, repoName, err := paths.DisectLeaf(repoPath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to disect path '%s': %w", repoPath, err)
|
||||
}
|
||||
scope := &types.Scope{SpacePath: spacePath, Repo: repoName}
|
||||
resource := &types.Resource{
|
||||
Type: enum.ResourceTypePipeline,
|
||||
Identifier: pipelineIdentifier,
|
||||
}
|
||||
return Check(ctx, authorizer, session, scope, resource, permission)
|
||||
}
|
||||
|
|
@ -1,36 +0,0 @@
|
|||
// Copyright 2023 Harness, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package auth
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/harness/gitness/app/auth"
|
||||
"github.com/harness/gitness/app/auth/authz"
|
||||
"github.com/harness/gitness/types"
|
||||
)
|
||||
|
||||
// CheckRegistry checks if a registry specific permission is granted for the current auth session
|
||||
// in the scope of its parent.
|
||||
// Returns nil if the permission is granted, otherwise returns an error.
|
||||
// NotAuthenticated, NotAuthorized, or any underlying error.
|
||||
func CheckRegistry(
|
||||
ctx context.Context,
|
||||
authorizer authz.Authorizer,
|
||||
session *auth.Session,
|
||||
permissionChecks ...types.PermissionCheck,
|
||||
) error {
|
||||
return CheckAll(ctx, authorizer, session, permissionChecks...)
|
||||
}
|
||||
|
|
@ -1,120 +0,0 @@
|
|||
// Copyright 2023 Harness, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package auth
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"slices"
|
||||
|
||||
"github.com/harness/gitness/app/auth"
|
||||
"github.com/harness/gitness/app/auth/authz"
|
||||
"github.com/harness/gitness/app/paths"
|
||||
"github.com/harness/gitness/errors"
|
||||
"github.com/harness/gitness/types"
|
||||
"github.com/harness/gitness/types/enum"
|
||||
)
|
||||
|
||||
// CheckRepo checks if a repo specific permission is granted for the current auth session
|
||||
// in the scope of its parent.
|
||||
// Returns nil if the permission is granted, otherwise returns an error.
|
||||
// NotAuthenticated, NotAuthorized, or any underlying error.
|
||||
func CheckRepo(
|
||||
ctx context.Context,
|
||||
authorizer authz.Authorizer,
|
||||
session *auth.Session,
|
||||
repo *types.RepositoryCore,
|
||||
permission enum.Permission,
|
||||
) error {
|
||||
parentSpace, name, err := paths.DisectLeaf(repo.Path)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to disect path '%s': %w", repo.Path, err)
|
||||
}
|
||||
|
||||
scope := &types.Scope{SpacePath: parentSpace}
|
||||
resource := &types.Resource{
|
||||
Type: enum.ResourceTypeRepo,
|
||||
Identifier: name,
|
||||
}
|
||||
|
||||
return Check(ctx, authorizer, session, scope, resource, permission)
|
||||
}
|
||||
|
||||
func IsRepoOwner(
|
||||
ctx context.Context,
|
||||
authorizer authz.Authorizer,
|
||||
session *auth.Session,
|
||||
repo *types.RepositoryCore,
|
||||
) (bool, error) {
|
||||
// for now we use repoedit as permission to verify if someone is a SpaceOwner and hence a RepoOwner.
|
||||
err := CheckRepo(ctx, authorizer, session, repo, enum.PermissionRepoEdit)
|
||||
if err != nil && !IsNoAccess(err) {
|
||||
return false, fmt.Errorf("failed to check access user access: %w", err)
|
||||
}
|
||||
|
||||
return err == nil, nil
|
||||
}
|
||||
|
||||
// CheckRepoState checks if requested permission is allowed given the state of the repository.
|
||||
func CheckRepoState(
|
||||
_ context.Context,
|
||||
_ *auth.Session,
|
||||
repo *types.RepositoryCore,
|
||||
reqPermission enum.Permission,
|
||||
additionalAllowedRepoStates ...enum.RepoState,
|
||||
) error {
|
||||
permissionsAllowedPerRepoState := map[enum.RepoState][]enum.Permission{
|
||||
enum.RepoStateActive: {
|
||||
enum.PermissionRepoView,
|
||||
enum.PermissionRepoCreate,
|
||||
enum.PermissionRepoEdit,
|
||||
enum.PermissionRepoPush,
|
||||
enum.PermissionRepoReview,
|
||||
enum.PermissionRepoDelete,
|
||||
enum.PermissionRepoReportCommitCheck,
|
||||
|
||||
enum.PermissionPipelineView,
|
||||
enum.PermissionPipelineExecute,
|
||||
enum.PermissionPipelineEdit,
|
||||
enum.PermissionPipelineDelete,
|
||||
|
||||
enum.PermissionServiceAccountView,
|
||||
},
|
||||
|
||||
enum.RepoStateArchived: {
|
||||
enum.PermissionRepoView,
|
||||
|
||||
enum.PermissionPipelineView,
|
||||
|
||||
enum.PermissionServiceAccountView,
|
||||
},
|
||||
|
||||
// allowed permissions for repos on transition states during import/migration are handled by their controller.
|
||||
enum.RepoStateGitImport: {},
|
||||
enum.RepoStateMigrateDataImport: {},
|
||||
enum.RepoStateMigrateGitPush: {},
|
||||
}
|
||||
|
||||
if len(additionalAllowedRepoStates) > 0 && slices.Contains(additionalAllowedRepoStates, repo.State) {
|
||||
return nil
|
||||
}
|
||||
|
||||
defaultAllowedPermissions := permissionsAllowedPerRepoState[repo.State]
|
||||
if !slices.Contains(defaultAllowedPermissions, reqPermission) {
|
||||
return errors.PreconditionFailedf("Operation is not allowed for repository in state %s", repo.State)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
@ -1,39 +0,0 @@
|
|||
// Copyright 2023 Harness, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package auth
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/harness/gitness/app/auth"
|
||||
"github.com/harness/gitness/app/auth/authz"
|
||||
"github.com/harness/gitness/types"
|
||||
"github.com/harness/gitness/types/enum"
|
||||
)
|
||||
|
||||
// CheckSecret checks if a repo specific permission is granted for the current auth session
|
||||
// in the scope of its parent.
|
||||
// Returns nil if the permission is granted, otherwise returns an error.
|
||||
// NotAuthenticated, NotAuthorized, or any underlying error.
|
||||
func CheckSecret(ctx context.Context, authorizer authz.Authorizer, session *auth.Session,
|
||||
parentPath, identifier string, permission enum.Permission) error {
|
||||
scope := &types.Scope{SpacePath: parentPath}
|
||||
resource := &types.Resource{
|
||||
Type: enum.ResourceTypeSecret,
|
||||
Identifier: identifier,
|
||||
}
|
||||
|
||||
return Check(ctx, authorizer, session, scope, resource, permission)
|
||||
}
|
||||
|
|
@ -1,40 +0,0 @@
|
|||
// Copyright 2023 Harness, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package auth
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/harness/gitness/app/auth"
|
||||
"github.com/harness/gitness/app/auth/authz"
|
||||
"github.com/harness/gitness/types"
|
||||
"github.com/harness/gitness/types/enum"
|
||||
)
|
||||
|
||||
// CheckService checks if a service specific permission is granted for the current auth session.
|
||||
// Returns nil if the permission is granted, otherwise returns an error.
|
||||
// NotAuthenticated, NotAuthorized, or any underlying error.
|
||||
func CheckService(ctx context.Context, authorizer authz.Authorizer, session *auth.Session,
|
||||
svc *types.Service, permission enum.Permission,
|
||||
) error {
|
||||
// a service exists outside any scope
|
||||
scope := &types.Scope{}
|
||||
resource := &types.Resource{
|
||||
Type: enum.ResourceTypeService,
|
||||
Identifier: svc.UID,
|
||||
}
|
||||
|
||||
return Check(ctx, authorizer, session, scope, resource, permission)
|
||||
}
|
||||
|
|
@ -1,37 +0,0 @@
|
|||
// Copyright 2023 Harness, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package auth
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/harness/gitness/app/auth"
|
||||
"github.com/harness/gitness/app/auth/authz"
|
||||
"github.com/harness/gitness/app/store"
|
||||
"github.com/harness/gitness/types/enum"
|
||||
)
|
||||
|
||||
// CheckServiceAccount checks if a service account specific permission is granted for the current auth session
|
||||
// in the scope of the parent.
|
||||
// Returns nil if the permission is granted, otherwise returns an error.
|
||||
// NotAuthenticated, NotAuthorized, or any underlying error.
|
||||
func CheckServiceAccount(ctx context.Context, authorizer authz.Authorizer, session *auth.Session,
|
||||
spaceStore store.SpaceStore, repoStore store.RepoStore, parentType enum.ParentResourceType, parentID int64,
|
||||
saUID string, permission enum.Permission,
|
||||
) error {
|
||||
return CheckChild(ctx, authorizer, session,
|
||||
spaceStore, repoStore, parentType, parentID,
|
||||
enum.ResourceTypeServiceAccount, saUID, permission)
|
||||
}
|
||||
|
|
@ -1,70 +0,0 @@
|
|||
// Copyright 2023 Harness, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package auth
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/harness/gitness/app/auth"
|
||||
"github.com/harness/gitness/app/auth/authz"
|
||||
"github.com/harness/gitness/app/paths"
|
||||
"github.com/harness/gitness/types"
|
||||
"github.com/harness/gitness/types/enum"
|
||||
)
|
||||
|
||||
// CheckSpace checks if a space specific permission is granted for the current auth session
|
||||
// in the scope of its parent.
|
||||
// Returns nil if permission is granted, otherwise returns NotAuthenticated, NotAuthorized, or the underlying error.
|
||||
func CheckSpace(
|
||||
ctx context.Context,
|
||||
authorizer authz.Authorizer,
|
||||
session *auth.Session,
|
||||
space *types.SpaceCore,
|
||||
permission enum.Permission,
|
||||
) error {
|
||||
parentSpace, name, err := paths.DisectLeaf(space.Path)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to disect path '%s': %w", space.Path, err)
|
||||
}
|
||||
|
||||
scope := &types.Scope{SpacePath: parentSpace}
|
||||
resource := &types.Resource{
|
||||
Type: enum.ResourceTypeSpace,
|
||||
Identifier: name,
|
||||
}
|
||||
|
||||
return Check(ctx, authorizer, session, scope, resource, permission)
|
||||
}
|
||||
|
||||
// CheckSpaceScope checks if a specific permission is granted for the current auth session
|
||||
// in the scope of the provided space.
|
||||
// Returns nil if permission is granted, otherwise returns NotAuthenticated, NotAuthorized, or the underlying error.
|
||||
func CheckSpaceScope(
|
||||
ctx context.Context,
|
||||
authorizer authz.Authorizer,
|
||||
session *auth.Session,
|
||||
space *types.SpaceCore,
|
||||
resourceType enum.ResourceType,
|
||||
permission enum.Permission,
|
||||
) error {
|
||||
scope := &types.Scope{SpacePath: space.Path}
|
||||
resource := &types.Resource{
|
||||
Type: resourceType,
|
||||
Identifier: "",
|
||||
}
|
||||
|
||||
return Check(ctx, authorizer, session, scope, resource, permission)
|
||||
}
|
||||
|
|
@ -1,39 +0,0 @@
|
|||
// Copyright 2023 Harness, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package auth
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/harness/gitness/app/auth"
|
||||
"github.com/harness/gitness/app/auth/authz"
|
||||
"github.com/harness/gitness/types"
|
||||
"github.com/harness/gitness/types/enum"
|
||||
)
|
||||
|
||||
// CheckTemplate checks if a repo specific permission is granted for the current auth session
|
||||
// in the scope of its parent.
|
||||
// Returns nil if the permission is granted, otherwise returns an error.
|
||||
// NotAuthenticated, NotAuthorized, or any underlying error.
|
||||
func CheckTemplate(ctx context.Context, authorizer authz.Authorizer, session *auth.Session,
|
||||
parentPath, identifier string, permission enum.Permission) error {
|
||||
scope := &types.Scope{SpacePath: parentPath}
|
||||
resource := &types.Resource{
|
||||
Type: enum.ResourceTypeTemplate,
|
||||
Identifier: identifier,
|
||||
}
|
||||
|
||||
return Check(ctx, authorizer, session, scope, resource, permission)
|
||||
}
|
||||
|
|
@ -1,40 +0,0 @@
|
|||
// Copyright 2023 Harness, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package auth
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/harness/gitness/app/auth"
|
||||
"github.com/harness/gitness/app/auth/authz"
|
||||
"github.com/harness/gitness/types"
|
||||
"github.com/harness/gitness/types/enum"
|
||||
)
|
||||
|
||||
// CheckUser checks if a user specific permission is granted for the current auth session.
|
||||
// Returns nil if the permission is granted, otherwise returns an error.
|
||||
// NotAuthenticated, NotAuthorized, or any underlying error.
|
||||
func CheckUser(ctx context.Context, authorizer authz.Authorizer, session *auth.Session,
|
||||
user *types.User, permission enum.Permission,
|
||||
) error {
|
||||
// a user exists outside any scope
|
||||
scope := &types.Scope{}
|
||||
resource := &types.Resource{
|
||||
Type: enum.ResourceTypeUser,
|
||||
Identifier: user.UID,
|
||||
}
|
||||
|
||||
return Check(ctx, authorizer, session, scope, resource, permission)
|
||||
}
|
||||
|
|
@ -1,65 +0,0 @@
|
|||
// Copyright 2023 Harness, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package check
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/harness/gitness/app/auth"
|
||||
"github.com/harness/gitness/types"
|
||||
"github.com/harness/gitness/types/enum"
|
||||
)
|
||||
|
||||
// ListChecks return an array of status check results for a commit in a repository.
|
||||
func (c *Controller) ListChecks(
|
||||
ctx context.Context,
|
||||
session *auth.Session,
|
||||
repoRef string,
|
||||
commitSHA string,
|
||||
opts types.CheckListOptions,
|
||||
) ([]types.Check, int, error) {
|
||||
repo, err := c.getRepoCheckAccess(ctx, session, repoRef, enum.PermissionRepoView)
|
||||
if err != nil {
|
||||
return nil, 0, fmt.Errorf("failed to acquire access to repo: %w", err)
|
||||
}
|
||||
|
||||
var checks []types.Check
|
||||
var count int
|
||||
|
||||
err = c.tx.WithTx(ctx, func(ctx context.Context) (err error) {
|
||||
checks, err = c.checkStore.List(ctx, repo.ID, commitSHA, opts)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to list status check results for repo=%s: %w", repo.Identifier, err)
|
||||
}
|
||||
|
||||
if opts.Page == 1 && len(checks) < opts.Size {
|
||||
count = len(checks)
|
||||
return nil
|
||||
}
|
||||
|
||||
count, err = c.checkStore.Count(ctx, repo.ID, commitSHA, opts)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to count status check results for repo=%s: %w", repo.Identifier, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
return checks, count, nil
|
||||
}
|
||||
|
|
@ -1,49 +0,0 @@
|
|||
// Copyright 2023 Harness, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package check
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/harness/gitness/app/auth"
|
||||
"github.com/harness/gitness/types"
|
||||
"github.com/harness/gitness/types/enum"
|
||||
)
|
||||
|
||||
// ListRecentChecks return an array of status check UIDs that have been run recently.
|
||||
func (c *Controller) ListRecentChecks(
|
||||
ctx context.Context,
|
||||
session *auth.Session,
|
||||
repoRef string,
|
||||
opts types.CheckRecentOptions,
|
||||
) ([]string, error) {
|
||||
repo, err := c.getRepoCheckAccess(ctx, session, repoRef, enum.PermissionRepoView)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to acquire access to repo: %w", err)
|
||||
}
|
||||
|
||||
if opts.Since == 0 {
|
||||
opts.Since = time.Now().Add(-30 * 24 * time.Hour).UnixMilli()
|
||||
}
|
||||
|
||||
checkIdentifiers, err := c.checkStore.ListRecent(ctx, repo.ID, opts)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to list status check results for repo=%s: %w", repo.Identifier, err)
|
||||
}
|
||||
|
||||
return checkIdentifiers, nil
|
||||
}
|
||||
|
|
@ -1,63 +0,0 @@
|
|||
// Copyright 2023 Harness, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package check
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/harness/gitness/app/auth"
|
||||
"github.com/harness/gitness/types"
|
||||
"github.com/harness/gitness/types/enum"
|
||||
)
|
||||
|
||||
// ListRecentChecksSpace return an array of status check UIDs that have been run recently.
|
||||
func (c *Controller) ListRecentChecksSpace(
|
||||
ctx context.Context,
|
||||
session *auth.Session,
|
||||
spaceRef string,
|
||||
recursive bool,
|
||||
opts types.CheckRecentOptions,
|
||||
) ([]string, error) {
|
||||
space, err := c.getSpaceCheckAccess(ctx, session, spaceRef, enum.PermissionSpaceView)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to acquire access to space: %w", err)
|
||||
}
|
||||
|
||||
if opts.Since == 0 {
|
||||
opts.Since = time.Now().Add(-30 * 24 * time.Hour).UnixMilli()
|
||||
}
|
||||
|
||||
var spaceIDs []int64
|
||||
if recursive {
|
||||
spaceIDs, err = c.spaceStore.GetDescendantsIDs(ctx, space.ID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get space descendants ids: %w", err)
|
||||
}
|
||||
} else {
|
||||
spaceIDs = append(spaceIDs, space.ID)
|
||||
}
|
||||
|
||||
checkIdentifiers, err := c.checkStore.ListRecentSpace(ctx, spaceIDs, opts)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf(
|
||||
"failed to list status check results for space=%s: %w",
|
||||
space.Identifier, err,
|
||||
)
|
||||
}
|
||||
|
||||
return checkIdentifiers, nil
|
||||
}
|
||||
|
|
@ -1,246 +0,0 @@
|
|||
// Copyright 2023 Harness, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package check
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"regexp"
|
||||
"time"
|
||||
|
||||
"github.com/harness/gitness/app/api/usererror"
|
||||
"github.com/harness/gitness/app/auth"
|
||||
events "github.com/harness/gitness/app/events/check"
|
||||
"github.com/harness/gitness/git"
|
||||
"github.com/harness/gitness/store"
|
||||
"github.com/harness/gitness/types"
|
||||
"github.com/harness/gitness/types/enum"
|
||||
)
|
||||
|
||||
type ReportInput struct {
|
||||
// TODO [CODE-1363]: remove after identifier migration.
|
||||
CheckUID string `json:"check_uid" deprecated:"true"`
|
||||
Identifier string `json:"identifier"`
|
||||
Status enum.CheckStatus `json:"status"`
|
||||
Summary string `json:"summary"`
|
||||
Link string `json:"link"`
|
||||
Payload types.CheckPayload `json:"payload"`
|
||||
|
||||
Started int64 `json:"started,omitempty"`
|
||||
Ended int64 `json:"ended,omitempty"`
|
||||
}
|
||||
|
||||
// TODO: Can we drop the '$' - depends on whether harness allows it.
|
||||
var regexpCheckIdentifier = "^[0-9a-zA-Z-_.$]{1,127}$"
|
||||
var matcherCheckIdentifier = regexp.MustCompile(regexpCheckIdentifier)
|
||||
|
||||
// Sanitize validates and sanitizes the ReportInput data.
|
||||
func (in *ReportInput) Sanitize(
|
||||
sanitizers map[enum.CheckPayloadKind]func(in *ReportInput, s *auth.Session) error, session *auth.Session,
|
||||
) error {
|
||||
// TODO [CODE-1363]: remove after identifier migration.
|
||||
if in.Identifier == "" {
|
||||
in.Identifier = in.CheckUID
|
||||
}
|
||||
|
||||
if in.Identifier == "" {
|
||||
return usererror.BadRequest("Identifier is missing")
|
||||
}
|
||||
|
||||
if !matcherCheckIdentifier.MatchString(in.Identifier) {
|
||||
return usererror.BadRequestf("Identifier must match the regular expression: %s", regexpCheckIdentifier)
|
||||
}
|
||||
|
||||
_, ok := in.Status.Sanitize()
|
||||
if !ok {
|
||||
return usererror.BadRequest("Invalid value provided for status check status")
|
||||
}
|
||||
|
||||
validatorFn, ok := sanitizers[in.Payload.Kind]
|
||||
if !ok {
|
||||
return usererror.BadRequest("Invalid value provided for the payload kind")
|
||||
}
|
||||
|
||||
// Validate and sanitize the input data based on version; Require a link... and similar operations.
|
||||
if err := validatorFn(in, session); err != nil {
|
||||
return fmt.Errorf("payload validation failed: %w", err)
|
||||
}
|
||||
|
||||
if in.Ended != 0 && in.Ended < in.Started {
|
||||
return usererror.BadRequest("Started time reported after ended time")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func SanitizeJSONPayload(source json.RawMessage, data any) (json.RawMessage, error) {
|
||||
if len(source) == 0 {
|
||||
return json.Marshal(data) // marshal the empty object
|
||||
}
|
||||
|
||||
decoder := json.NewDecoder(bytes.NewReader(source))
|
||||
decoder.DisallowUnknownFields()
|
||||
|
||||
if err := decoder.Decode(&data); err != nil {
|
||||
return nil, usererror.BadRequestf("Payload data doesn't match the required format: %s", err.Error())
|
||||
}
|
||||
|
||||
buffer := bytes.NewBuffer(nil)
|
||||
buffer.Grow(512)
|
||||
|
||||
encoder := json.NewEncoder(buffer)
|
||||
encoder.SetEscapeHTML(false)
|
||||
if err := encoder.Encode(data); err != nil {
|
||||
return nil, fmt.Errorf("failed to sanitize json payload: %w", err)
|
||||
}
|
||||
|
||||
result := buffer.Bytes()
|
||||
|
||||
if result[len(result)-1] == '\n' {
|
||||
result = result[:len(result)-1]
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// Report modifies an existing or creates a new (if none yet exists) status check report for a specific commit.
|
||||
func (c *Controller) Report(
|
||||
ctx context.Context,
|
||||
session *auth.Session,
|
||||
repoRef string,
|
||||
commitSHA string,
|
||||
in *ReportInput,
|
||||
metadata map[string]string,
|
||||
) (*types.Check, error) {
|
||||
repo, err := c.getRepoCheckAccess(ctx, session, repoRef, enum.PermissionRepoReportCommitCheck)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to acquire access to repo: %w", err)
|
||||
}
|
||||
|
||||
if errValidate := in.Sanitize(c.sanitizers, session); errValidate != nil {
|
||||
return nil, errValidate
|
||||
}
|
||||
|
||||
if !git.ValidateCommitSHA(commitSHA) {
|
||||
return nil, usererror.BadRequest("Invalid commit SHA provided")
|
||||
}
|
||||
|
||||
_, err = c.git.GetCommit(ctx, &git.GetCommitParams{
|
||||
ReadParams: git.ReadParams{RepoUID: repo.GitUID},
|
||||
Revision: commitSHA,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to commit sha=%s: %w", commitSHA, err)
|
||||
}
|
||||
|
||||
now := time.Now().UnixMilli()
|
||||
|
||||
metadataJSON, _ := json.Marshal(metadata)
|
||||
|
||||
existingCheck, err := c.checkStore.FindByIdentifier(ctx, repo.ID, commitSHA, in.Identifier)
|
||||
|
||||
if err != nil && !errors.Is(err, store.ErrResourceNotFound) {
|
||||
return nil, fmt.Errorf("failed to find existing check for Identifier %q: %w", in.Identifier, err)
|
||||
}
|
||||
|
||||
started := getStartTime(in, existingCheck, now)
|
||||
ended := getEndTime(in, now)
|
||||
|
||||
statusCheckReport := &types.Check{
|
||||
CreatedBy: session.Principal.ID,
|
||||
Created: now,
|
||||
Updated: now,
|
||||
RepoID: repo.ID,
|
||||
CommitSHA: commitSHA,
|
||||
Identifier: in.Identifier,
|
||||
Status: in.Status,
|
||||
Summary: in.Summary,
|
||||
Link: in.Link,
|
||||
Payload: in.Payload,
|
||||
Metadata: metadataJSON,
|
||||
ReportedBy: session.Principal.ToPrincipalInfo(),
|
||||
Started: started,
|
||||
Ended: ended,
|
||||
}
|
||||
|
||||
err = c.checkStore.Upsert(ctx, statusCheckReport)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to upsert status check result for repo=%s: %w", repo.Identifier, err)
|
||||
}
|
||||
|
||||
c.eventReporter.Reported(ctx, &events.ReportedPayload{
|
||||
Base: events.Base{
|
||||
RepoID: repo.ID,
|
||||
SHA: commitSHA,
|
||||
},
|
||||
Identifier: in.Identifier,
|
||||
Status: in.Status,
|
||||
})
|
||||
|
||||
c.sseStreamer.Publish(ctx, repo.ParentID, enum.SSETypeStatusCheckReportUpdated, statusCheckReport)
|
||||
|
||||
return statusCheckReport, nil
|
||||
}
|
||||
|
||||
func getStartTime(in *ReportInput, check types.Check, now int64) int64 {
|
||||
// start value came in api
|
||||
if in.Started != 0 {
|
||||
return in.Started
|
||||
}
|
||||
// in.started has no value we smartly put value for started
|
||||
|
||||
// in case of pending we assume check has not started running
|
||||
if in.Status == enum.CheckStatusPending {
|
||||
return 0
|
||||
}
|
||||
|
||||
// new check
|
||||
if check.Started == 0 {
|
||||
return now
|
||||
}
|
||||
|
||||
// The incoming check status can now be running or terminal.
|
||||
|
||||
// in case we already have running status we don't update time else we return current time as check has started
|
||||
// running.
|
||||
if check.Status == enum.CheckStatusRunning {
|
||||
return check.Started
|
||||
}
|
||||
|
||||
// Note: In case of reporting terminal statuses again and again we have assumed its
|
||||
// a report of new status check everytime.
|
||||
|
||||
// In case someone reports any status before marking running return current time.
|
||||
// This can happen if someone only reports terminal status or marks running status again after terminal.
|
||||
return now
|
||||
}
|
||||
|
||||
func getEndTime(in *ReportInput, now int64) int64 {
|
||||
// end value came in api
|
||||
if in.Ended != 0 {
|
||||
return in.Ended
|
||||
}
|
||||
|
||||
// if we get terminal status i.e. error, failure or success we return current time.
|
||||
if in.Status.IsCompleted() {
|
||||
return now
|
||||
}
|
||||
|
||||
// in case of other status we return value as 0, which means we have not yet completed the check.
|
||||
return 0
|
||||
}
|
||||
|
|
@ -1,215 +0,0 @@
|
|||
// Copyright 2023 Harness, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package check
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/harness/gitness/types"
|
||||
"github.com/harness/gitness/types/enum"
|
||||
)
|
||||
|
||||
func Test_getStartedTime(t *testing.T) {
|
||||
type args struct {
|
||||
in *ReportInput
|
||||
check types.Check
|
||||
now int64
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want int64
|
||||
}{
|
||||
{
|
||||
name: "nothing to pending",
|
||||
args: args{
|
||||
in: &ReportInput{Status: enum.CheckStatusPending},
|
||||
check: types.Check{},
|
||||
now: 1234,
|
||||
},
|
||||
want: 0,
|
||||
},
|
||||
|
||||
{
|
||||
name: "nothing to running",
|
||||
args: args{
|
||||
in: &ReportInput{Status: enum.CheckStatusRunning},
|
||||
check: types.Check{},
|
||||
now: 1234,
|
||||
},
|
||||
want: 1234,
|
||||
},
|
||||
{
|
||||
name: "nothing to completed",
|
||||
args: args{
|
||||
in: &ReportInput{Status: enum.CheckStatusSuccess},
|
||||
check: types.Check{},
|
||||
now: 1234,
|
||||
},
|
||||
want: 1234,
|
||||
},
|
||||
{
|
||||
name: "nothing to completed1",
|
||||
args: args{
|
||||
in: &ReportInput{Status: enum.CheckStatusSuccess, Started: 1},
|
||||
check: types.Check{},
|
||||
now: 1234,
|
||||
},
|
||||
want: 1,
|
||||
},
|
||||
{
|
||||
name: "pending to pending",
|
||||
args: args{
|
||||
in: &ReportInput{Status: enum.CheckStatusPending, Started: 1},
|
||||
check: types.Check{Status: enum.CheckStatusPending, Started: 0},
|
||||
now: 1234,
|
||||
},
|
||||
want: 1,
|
||||
},
|
||||
{
|
||||
name: "pending to pending1",
|
||||
args: args{
|
||||
in: &ReportInput{Status: enum.CheckStatusPending},
|
||||
check: types.Check{Status: enum.CheckStatusPending, Started: 0},
|
||||
now: 1234,
|
||||
},
|
||||
want: 0,
|
||||
},
|
||||
{
|
||||
name: "pending to running",
|
||||
args: args{
|
||||
in: &ReportInput{Status: enum.CheckStatusRunning},
|
||||
check: types.Check{Status: enum.CheckStatusPending, Started: 0},
|
||||
now: 1234,
|
||||
},
|
||||
want: 1234,
|
||||
},
|
||||
{
|
||||
name: "pending to running1",
|
||||
args: args{
|
||||
in: &ReportInput{Status: enum.CheckStatusRunning, Started: 1},
|
||||
check: types.Check{Status: enum.CheckStatusPending, Started: 0},
|
||||
now: 1234,
|
||||
},
|
||||
want: 1,
|
||||
},
|
||||
{
|
||||
name: "pending to completed",
|
||||
args: args{
|
||||
in: &ReportInput{Status: enum.CheckStatusSuccess, Started: 1},
|
||||
check: types.Check{Status: enum.CheckStatusPending, Started: 0},
|
||||
now: 1234,
|
||||
},
|
||||
want: 1,
|
||||
},
|
||||
{
|
||||
name: "pending to completed1",
|
||||
args: args{
|
||||
in: &ReportInput{Status: enum.CheckStatusSuccess},
|
||||
check: types.Check{Status: enum.CheckStatusPending, Started: 0},
|
||||
now: 1234,
|
||||
},
|
||||
want: 1234,
|
||||
},
|
||||
{
|
||||
name: "running to pending",
|
||||
args: args{
|
||||
in: &ReportInput{Status: enum.CheckStatusPending, Started: 1},
|
||||
check: types.Check{Status: enum.CheckStatusRunning, Started: 9876},
|
||||
now: 1234,
|
||||
},
|
||||
want: 1,
|
||||
},
|
||||
{
|
||||
name: "running to pending1",
|
||||
args: args{
|
||||
in: &ReportInput{Status: enum.CheckStatusPending},
|
||||
check: types.Check{Status: enum.CheckStatusRunning, Started: 9876},
|
||||
now: 1234,
|
||||
},
|
||||
want: 0,
|
||||
},
|
||||
{
|
||||
name: "running to running",
|
||||
args: args{
|
||||
in: &ReportInput{Status: enum.CheckStatusRunning},
|
||||
check: types.Check{Status: enum.CheckStatusRunning, Started: 9876},
|
||||
now: 1234,
|
||||
},
|
||||
want: 9876,
|
||||
},
|
||||
{
|
||||
name: "running to running1",
|
||||
args: args{
|
||||
in: &ReportInput{Status: enum.CheckStatusRunning, Started: 1},
|
||||
check: types.Check{Status: enum.CheckStatusRunning, Started: 9876},
|
||||
now: 1234,
|
||||
},
|
||||
want: 1,
|
||||
},
|
||||
{
|
||||
name: "running to completed",
|
||||
args: args{
|
||||
in: &ReportInput{Status: enum.CheckStatusSuccess},
|
||||
check: types.Check{Status: enum.CheckStatusRunning, Started: 9876},
|
||||
now: 1234,
|
||||
},
|
||||
want: 9876,
|
||||
},
|
||||
{
|
||||
name: "running to completed",
|
||||
args: args{
|
||||
in: &ReportInput{Status: enum.CheckStatusSuccess, Started: 1},
|
||||
check: types.Check{Status: enum.CheckStatusRunning, Started: 9876},
|
||||
now: 1234,
|
||||
},
|
||||
want: 1,
|
||||
},
|
||||
{
|
||||
name: "completed to pending",
|
||||
args: args{
|
||||
in: &ReportInput{Status: enum.CheckStatusPending},
|
||||
check: types.Check{Status: enum.CheckStatusSuccess, Started: 9876},
|
||||
now: 1234,
|
||||
},
|
||||
want: 0,
|
||||
},
|
||||
{
|
||||
name: "completed to running",
|
||||
args: args{
|
||||
in: &ReportInput{Status: enum.CheckStatusRunning},
|
||||
check: types.Check{Status: enum.CheckStatusSuccess, Started: 9876},
|
||||
now: 1234,
|
||||
},
|
||||
want: 1234,
|
||||
},
|
||||
{
|
||||
name: "completed to completed",
|
||||
args: args{
|
||||
in: &ReportInput{Status: enum.CheckStatusSuccess},
|
||||
check: types.Check{Status: enum.CheckStatusSuccess, Started: 9876},
|
||||
now: 1234,
|
||||
},
|
||||
want: 1234,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if got := getStartTime(tt.args.in, tt.args.check, tt.args.now); got != tt.want {
|
||||
t.Errorf("getStartTime() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
@ -1,110 +0,0 @@
|
|||
// Copyright 2023 Harness, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package check
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
apiauth "github.com/harness/gitness/app/api/auth"
|
||||
"github.com/harness/gitness/app/api/controller/space"
|
||||
"github.com/harness/gitness/app/api/usererror"
|
||||
"github.com/harness/gitness/app/auth"
|
||||
"github.com/harness/gitness/app/auth/authz"
|
||||
checkevents "github.com/harness/gitness/app/events/check"
|
||||
"github.com/harness/gitness/app/services/refcache"
|
||||
"github.com/harness/gitness/app/sse"
|
||||
"github.com/harness/gitness/app/store"
|
||||
"github.com/harness/gitness/git"
|
||||
"github.com/harness/gitness/store/database/dbtx"
|
||||
"github.com/harness/gitness/types"
|
||||
"github.com/harness/gitness/types/enum"
|
||||
)
|
||||
|
||||
type Controller struct {
|
||||
tx dbtx.Transactor
|
||||
authorizer authz.Authorizer
|
||||
spaceStore store.SpaceStore
|
||||
checkStore store.CheckStore
|
||||
spaceFinder refcache.SpaceFinder
|
||||
repoFinder refcache.RepoFinder
|
||||
git git.Interface
|
||||
sanitizers map[enum.CheckPayloadKind]func(in *ReportInput, s *auth.Session) error
|
||||
sseStreamer sse.Streamer
|
||||
eventReporter *checkevents.Reporter
|
||||
}
|
||||
|
||||
func NewController(
|
||||
tx dbtx.Transactor,
|
||||
authorizer authz.Authorizer,
|
||||
spaceStore store.SpaceStore,
|
||||
checkStore store.CheckStore,
|
||||
spaceFinder refcache.SpaceFinder,
|
||||
repoFinder refcache.RepoFinder,
|
||||
git git.Interface,
|
||||
sanitizers map[enum.CheckPayloadKind]func(in *ReportInput, s *auth.Session) error,
|
||||
sseStreamer sse.Streamer,
|
||||
eventReporter *checkevents.Reporter,
|
||||
) *Controller {
|
||||
return &Controller{
|
||||
tx: tx,
|
||||
authorizer: authorizer,
|
||||
spaceStore: spaceStore,
|
||||
checkStore: checkStore,
|
||||
spaceFinder: spaceFinder,
|
||||
repoFinder: repoFinder,
|
||||
git: git,
|
||||
sanitizers: sanitizers,
|
||||
sseStreamer: sseStreamer,
|
||||
eventReporter: eventReporter,
|
||||
}
|
||||
}
|
||||
|
||||
//nolint:unparam
|
||||
func (c *Controller) getRepoCheckAccess(
|
||||
ctx context.Context,
|
||||
session *auth.Session,
|
||||
repoRef string,
|
||||
reqPermission enum.Permission,
|
||||
allowedRepoStates ...enum.RepoState,
|
||||
) (*types.RepositoryCore, error) {
|
||||
if repoRef == "" {
|
||||
return nil, usererror.BadRequest("A valid repository reference must be provided.")
|
||||
}
|
||||
|
||||
repo, err := c.repoFinder.FindByRef(ctx, repoRef)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to find repository: %w", err)
|
||||
}
|
||||
|
||||
if err := apiauth.CheckRepoState(ctx, session, repo, reqPermission, allowedRepoStates...); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err = apiauth.CheckRepo(ctx, c.authorizer, session, repo, reqPermission); err != nil {
|
||||
return nil, fmt.Errorf("access check failed: %w", err)
|
||||
}
|
||||
|
||||
return repo, nil
|
||||
}
|
||||
|
||||
func (c *Controller) getSpaceCheckAccess(
|
||||
ctx context.Context,
|
||||
session *auth.Session,
|
||||
spaceRef string,
|
||||
permission enum.Permission,
|
||||
) (*types.SpaceCore, error) {
|
||||
return space.GetSpaceCheckAuth(ctx, c.spaceFinder, c.authorizer, session, spaceRef, permission)
|
||||
}
|
||||
|
|
@ -1,75 +0,0 @@
|
|||
// Copyright 2023 Harness, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package check
|
||||
|
||||
import (
|
||||
"github.com/harness/gitness/app/api/usererror"
|
||||
"github.com/harness/gitness/app/auth"
|
||||
"github.com/harness/gitness/types"
|
||||
"github.com/harness/gitness/types/enum"
|
||||
)
|
||||
|
||||
func ProvideCheckSanitizers() map[enum.CheckPayloadKind]func(in *ReportInput, s *auth.Session) error {
|
||||
registeredCheckSanitizers := make(map[enum.CheckPayloadKind]func(in *ReportInput, s *auth.Session) error)
|
||||
|
||||
registeredCheckSanitizers[enum.CheckPayloadKindEmpty] = createEmptyPayloadSanitizer()
|
||||
|
||||
registeredCheckSanitizers[enum.CheckPayloadKindRaw] = createRawPayloadSanitizer()
|
||||
|
||||
// Markdown and Raw are the same.
|
||||
registeredCheckSanitizers[enum.CheckPayloadKindMarkdown] = registeredCheckSanitizers[enum.CheckPayloadKindRaw]
|
||||
|
||||
registeredCheckSanitizers[enum.CheckPayloadKindPipeline] = createPipelinePayloadSanitizer()
|
||||
return registeredCheckSanitizers
|
||||
}
|
||||
|
||||
func createEmptyPayloadSanitizer() func(in *ReportInput, _ *auth.Session) error {
|
||||
return func(in *ReportInput, _ *auth.Session) error {
|
||||
// the default payload kind (empty) does not support the payload data: clear it here
|
||||
in.Payload.Version = ""
|
||||
in.Payload.Data = []byte("{}")
|
||||
|
||||
if in.Link == "" { // the link is mandatory as there is nothing in the payload
|
||||
return usererror.BadRequest("Link is missing")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func createRawPayloadSanitizer() func(in *ReportInput, _ *auth.Session) error {
|
||||
return func(in *ReportInput, _ *auth.Session) error {
|
||||
// the text payload kinds (raw and markdown) do not support the version
|
||||
if in.Payload.Version != "" {
|
||||
return usererror.BadRequestf("Payload version must be empty for the payload kind '%s'",
|
||||
in.Payload.Kind)
|
||||
}
|
||||
|
||||
payloadDataJSON, err := SanitizeJSONPayload(in.Payload.Data, &types.CheckPayloadText{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
in.Payload.Data = payloadDataJSON
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func createPipelinePayloadSanitizer() func(in *ReportInput, _ *auth.Session) error {
|
||||
return func(_ *ReportInput, _ *auth.Session) error {
|
||||
return usererror.BadRequest("Kind cannot be pipeline for external checks")
|
||||
}
|
||||
}
|
||||
|
|
@ -1,61 +0,0 @@
|
|||
// Copyright 2023 Harness, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package check
|
||||
|
||||
import (
|
||||
"github.com/harness/gitness/app/auth"
|
||||
"github.com/harness/gitness/app/auth/authz"
|
||||
checkevents "github.com/harness/gitness/app/events/check"
|
||||
"github.com/harness/gitness/app/services/refcache"
|
||||
"github.com/harness/gitness/app/sse"
|
||||
"github.com/harness/gitness/app/store"
|
||||
"github.com/harness/gitness/git"
|
||||
"github.com/harness/gitness/store/database/dbtx"
|
||||
"github.com/harness/gitness/types/enum"
|
||||
|
||||
"github.com/google/wire"
|
||||
)
|
||||
|
||||
// WireSet provides a wire set for this package.
|
||||
var WireSet = wire.NewSet(
|
||||
ProvideCheckSanitizers,
|
||||
ProvideController,
|
||||
)
|
||||
|
||||
func ProvideController(
|
||||
tx dbtx.Transactor,
|
||||
authorizer authz.Authorizer,
|
||||
spaceStore store.SpaceStore,
|
||||
checkStore store.CheckStore,
|
||||
spaceFinder refcache.SpaceFinder,
|
||||
repoFinder refcache.RepoFinder,
|
||||
git git.Interface,
|
||||
sanitizers map[enum.CheckPayloadKind]func(in *ReportInput, s *auth.Session) error,
|
||||
sseStreamer sse.Streamer,
|
||||
eventReporter *checkevents.Reporter,
|
||||
) *Controller {
|
||||
return NewController(
|
||||
tx,
|
||||
authorizer,
|
||||
spaceStore,
|
||||
checkStore,
|
||||
spaceFinder,
|
||||
repoFinder,
|
||||
git,
|
||||
sanitizers,
|
||||
sseStreamer,
|
||||
eventReporter,
|
||||
)
|
||||
}
|
||||
|
|
@ -1,43 +0,0 @@
|
|||
// Copyright 2023 Harness, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package connector
|
||||
|
||||
import (
|
||||
"github.com/harness/gitness/app/auth/authz"
|
||||
"github.com/harness/gitness/app/connector"
|
||||
"github.com/harness/gitness/app/services/refcache"
|
||||
"github.com/harness/gitness/app/store"
|
||||
)
|
||||
|
||||
type Controller struct {
|
||||
connectorStore store.ConnectorStore
|
||||
connectorService *connector.Service
|
||||
spaceFinder refcache.SpaceFinder
|
||||
authorizer authz.Authorizer
|
||||
}
|
||||
|
||||
func NewController(
|
||||
authorizer authz.Authorizer,
|
||||
connectorStore store.ConnectorStore,
|
||||
connectorService *connector.Service,
|
||||
spaceFinder refcache.SpaceFinder,
|
||||
) *Controller {
|
||||
return &Controller{
|
||||
connectorStore: connectorStore,
|
||||
connectorService: connectorService,
|
||||
spaceFinder: spaceFinder,
|
||||
authorizer: authorizer,
|
||||
}
|
||||
}
|
||||
|
|
@ -1,116 +0,0 @@
|
|||
// Copyright 2023 Harness, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package connector
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
apiauth "github.com/harness/gitness/app/api/auth"
|
||||
"github.com/harness/gitness/app/api/usererror"
|
||||
"github.com/harness/gitness/app/auth"
|
||||
"github.com/harness/gitness/types"
|
||||
"github.com/harness/gitness/types/check"
|
||||
"github.com/harness/gitness/types/enum"
|
||||
)
|
||||
|
||||
var (
|
||||
// errConnectorRequiresParent if the user tries to create a connector without a parent space.
|
||||
errConnectorRequiresParent = usererror.BadRequest(
|
||||
"Parent space required - standalone connector are not supported.")
|
||||
)
|
||||
|
||||
type CreateInput struct {
|
||||
Description string `json:"description"`
|
||||
SpaceRef string `json:"space_ref"` // Ref of the parent space
|
||||
Identifier string `json:"identifier"`
|
||||
Type enum.ConnectorType `json:"type"`
|
||||
types.ConnectorConfig
|
||||
}
|
||||
|
||||
func (c *Controller) Create(
|
||||
ctx context.Context,
|
||||
session *auth.Session,
|
||||
in *CreateInput,
|
||||
) (*types.Connector, error) {
|
||||
if err := in.validate(); err != nil {
|
||||
return nil, fmt.Errorf("failed to sanitize input: %w", err)
|
||||
}
|
||||
|
||||
parentSpace, err := c.spaceFinder.FindByRef(ctx, in.SpaceRef)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to find parent by ref: %w", err)
|
||||
}
|
||||
|
||||
err = apiauth.CheckConnector(
|
||||
ctx,
|
||||
c.authorizer,
|
||||
session,
|
||||
parentSpace.Path,
|
||||
"",
|
||||
enum.PermissionConnectorEdit,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
now := time.Now().UnixMilli()
|
||||
|
||||
connector := &types.Connector{
|
||||
Description: in.Description,
|
||||
CreatedBy: session.Principal.ID,
|
||||
Type: in.Type,
|
||||
SpaceID: parentSpace.ID,
|
||||
Identifier: in.Identifier,
|
||||
Created: now,
|
||||
Updated: now,
|
||||
Version: 0,
|
||||
ConnectorConfig: in.ConnectorConfig,
|
||||
}
|
||||
|
||||
err = c.connectorStore.Create(ctx, connector)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("connector creation failed: %w", err)
|
||||
}
|
||||
|
||||
return connector, nil
|
||||
}
|
||||
|
||||
func (in *CreateInput) validate() error {
|
||||
parentRefAsID, err := strconv.ParseInt(in.SpaceRef, 10, 64)
|
||||
if (err == nil && parentRefAsID <= 0) || (len(strings.TrimSpace(in.SpaceRef)) == 0) {
|
||||
return errConnectorRequiresParent
|
||||
}
|
||||
|
||||
// check that the connector type is valid
|
||||
if _, ok := in.Type.Sanitize(); !ok {
|
||||
return usererror.BadRequest("Invalid connector type")
|
||||
}
|
||||
|
||||
// if the connector type is valid, validate the connector config
|
||||
if err := in.ConnectorConfig.Validate(in.Type); err != nil {
|
||||
return usererror.BadRequest(fmt.Sprintf("invalid connector config: %s", err.Error()))
|
||||
}
|
||||
|
||||
if err := check.Identifier(in.Identifier); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
in.Description = strings.TrimSpace(in.Description)
|
||||
return check.Description(in.Description)
|
||||
}
|
||||
|
|
@ -1,46 +0,0 @@
|
|||
// Copyright 2023 Harness, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package connector
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
apiauth "github.com/harness/gitness/app/api/auth"
|
||||
"github.com/harness/gitness/app/auth"
|
||||
"github.com/harness/gitness/types/enum"
|
||||
)
|
||||
|
||||
func (c *Controller) Delete(
|
||||
ctx context.Context,
|
||||
session *auth.Session,
|
||||
spaceRef string,
|
||||
identifier string,
|
||||
) error {
|
||||
space, err := c.spaceFinder.FindByRef(ctx, spaceRef)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to find space: %w", err)
|
||||
}
|
||||
|
||||
err = apiauth.CheckConnector(ctx, c.authorizer, session, space.Path, identifier, enum.PermissionConnectorDelete)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to authorize: %w", err)
|
||||
}
|
||||
err = c.connectorStore.DeleteByIdentifier(ctx, space.ID, identifier)
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not delete connector: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
@ -1,49 +0,0 @@
|
|||
// Copyright 2023 Harness, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package connector
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
apiauth "github.com/harness/gitness/app/api/auth"
|
||||
"github.com/harness/gitness/app/auth"
|
||||
"github.com/harness/gitness/types"
|
||||
"github.com/harness/gitness/types/enum"
|
||||
)
|
||||
|
||||
func (c *Controller) Find(
|
||||
ctx context.Context,
|
||||
session *auth.Session,
|
||||
spaceRef string,
|
||||
identifier string,
|
||||
) (*types.Connector, error) {
|
||||
space, err := c.spaceFinder.FindByRef(ctx, spaceRef)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to find space: %w", err)
|
||||
}
|
||||
|
||||
err = apiauth.CheckConnector(ctx, c.authorizer, session, space.Path, identifier, enum.PermissionConnectorView)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to authorize: %w", err)
|
||||
}
|
||||
|
||||
connector, err := c.connectorStore.FindByIdentifier(ctx, space.ID, identifier)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to find connector: %w", err)
|
||||
}
|
||||
|
||||
return connector, nil
|
||||
}
|
||||
|
|
@ -1,67 +0,0 @@
|
|||
// Copyright 2023 Harness, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package connector
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
apiauth "github.com/harness/gitness/app/api/auth"
|
||||
"github.com/harness/gitness/app/auth"
|
||||
"github.com/harness/gitness/types"
|
||||
"github.com/harness/gitness/types/enum"
|
||||
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
func (c *Controller) Test(
|
||||
ctx context.Context,
|
||||
session *auth.Session,
|
||||
spaceRef string,
|
||||
identifier string,
|
||||
) (types.ConnectorTestResponse, error) {
|
||||
space, err := c.spaceFinder.FindByRef(ctx, spaceRef)
|
||||
if err != nil {
|
||||
return types.ConnectorTestResponse{}, fmt.Errorf("failed to find space: %w", err)
|
||||
}
|
||||
|
||||
err = apiauth.CheckConnector(ctx, c.authorizer, session, space.Path, identifier, enum.PermissionConnectorAccess)
|
||||
if err != nil {
|
||||
return types.ConnectorTestResponse{}, fmt.Errorf("failed to authorize: %w", err)
|
||||
}
|
||||
|
||||
connector, err := c.connectorStore.FindByIdentifier(ctx, space.ID, identifier)
|
||||
if err != nil {
|
||||
return types.ConnectorTestResponse{}, fmt.Errorf("failed to find connector: %w", err)
|
||||
}
|
||||
|
||||
resp, err := c.connectorService.Test(ctx, connector)
|
||||
if err != nil {
|
||||
return types.ConnectorTestResponse{}, err
|
||||
}
|
||||
// Try to update connector last test information in DB. Log but ignore errors
|
||||
_, err = c.connectorStore.UpdateOptLock(ctx, connector, func(original *types.Connector) error {
|
||||
original.LastTestErrorMsg = resp.ErrorMsg
|
||||
original.LastTestStatus = resp.Status
|
||||
original.LastTestAttempt = time.Now().UnixMilli()
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
log.Ctx(ctx).Warn().Err(err).Msg("failed to update test connection information in connector")
|
||||
}
|
||||
|
||||
return resp, nil
|
||||
}
|
||||
|
|
@ -1,100 +0,0 @@
|
|||
// Copyright 2023 Harness, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package connector
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
apiauth "github.com/harness/gitness/app/api/auth"
|
||||
"github.com/harness/gitness/app/api/usererror"
|
||||
"github.com/harness/gitness/app/auth"
|
||||
"github.com/harness/gitness/types"
|
||||
"github.com/harness/gitness/types/check"
|
||||
"github.com/harness/gitness/types/enum"
|
||||
)
|
||||
|
||||
// UpdateInput is used for updating a connector.
|
||||
type UpdateInput struct {
|
||||
Identifier *string `json:"identifier"`
|
||||
Description *string `json:"description"`
|
||||
*types.ConnectorConfig
|
||||
}
|
||||
|
||||
func (c *Controller) Update(
|
||||
ctx context.Context,
|
||||
session *auth.Session,
|
||||
spaceRef string,
|
||||
identifier string,
|
||||
in *UpdateInput,
|
||||
) (*types.Connector, error) {
|
||||
if err := in.validate(); err != nil {
|
||||
return nil, fmt.Errorf("failed to sanitize input: %w", err)
|
||||
}
|
||||
|
||||
space, err := c.spaceFinder.FindByRef(ctx, spaceRef)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to find space: %w", err)
|
||||
}
|
||||
|
||||
err = apiauth.CheckConnector(ctx, c.authorizer, session, space.Path, identifier, enum.PermissionConnectorEdit)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to authorize: %w", err)
|
||||
}
|
||||
|
||||
connector, err := c.connectorStore.FindByIdentifier(ctx, space.ID, identifier)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to find connector: %w", err)
|
||||
}
|
||||
|
||||
return c.connectorStore.UpdateOptLock(ctx, connector, func(original *types.Connector) error {
|
||||
if in.Identifier != nil {
|
||||
original.Identifier = *in.Identifier
|
||||
}
|
||||
if in.Description != nil {
|
||||
original.Description = *in.Description
|
||||
}
|
||||
// TODO: See if this can be made better. The PATCH API supports partial updates so
|
||||
// currently we keep all the top level fields the same unless they are explicitly provided.
|
||||
// The connector config is a nested field so we only check whether it's provided at the top level, and not
|
||||
// all the fields inside the config. Maybe PUT/POST would be a better option here?
|
||||
// We can revisit this once we start adding more connectors.
|
||||
if in.ConnectorConfig != nil {
|
||||
if err := in.ConnectorConfig.Validate(connector.Type); err != nil {
|
||||
return usererror.BadRequestf("Failed to validate connector config: %s", err.Error())
|
||||
}
|
||||
original.ConnectorConfig = *in.ConnectorConfig
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
func (in *UpdateInput) validate() error {
|
||||
if in.Identifier != nil {
|
||||
if err := check.Identifier(*in.Identifier); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if in.Description != nil {
|
||||
*in.Description = strings.TrimSpace(*in.Description)
|
||||
if err := check.Description(*in.Description); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
@ -1,38 +0,0 @@
|
|||
// Copyright 2023 Harness, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package connector
|
||||
|
||||
import (
|
||||
"github.com/harness/gitness/app/auth/authz"
|
||||
"github.com/harness/gitness/app/connector"
|
||||
"github.com/harness/gitness/app/services/refcache"
|
||||
"github.com/harness/gitness/app/store"
|
||||
|
||||
"github.com/google/wire"
|
||||
)
|
||||
|
||||
// WireSet provides a wire set for this package.
|
||||
var WireSet = wire.NewSet(
|
||||
ProvideController,
|
||||
)
|
||||
|
||||
func ProvideController(
|
||||
connectorStore store.ConnectorStore,
|
||||
connectorService *connector.Service,
|
||||
authorizer authz.Authorizer,
|
||||
spaceFinder refcache.SpaceFinder,
|
||||
) *Controller {
|
||||
return NewController(authorizer, connectorStore, connectorService, spaceFinder)
|
||||
}
|
||||
|
|
@ -1,69 +0,0 @@
|
|||
// Copyright 2023 Harness, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package execution
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/harness/gitness/app/auth"
|
||||
"github.com/harness/gitness/app/pipeline/checks"
|
||||
"github.com/harness/gitness/types"
|
||||
"github.com/harness/gitness/types/enum"
|
||||
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
func (c *Controller) Cancel(
|
||||
ctx context.Context,
|
||||
session *auth.Session,
|
||||
repoRef string,
|
||||
pipelineIdentifier string,
|
||||
executionNum int64,
|
||||
) (*types.Execution, error) {
|
||||
repo, err := c.getRepoCheckPipelineAccess(
|
||||
ctx,
|
||||
session,
|
||||
repoRef,
|
||||
pipelineIdentifier,
|
||||
enum.PermissionPipelineExecute,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
pipeline, err := c.pipelineStore.FindByIdentifier(ctx, repo.ID, pipelineIdentifier)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to find pipeline: %w", err)
|
||||
}
|
||||
|
||||
execution, err := c.executionStore.FindByNumber(ctx, pipeline.ID, executionNum)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to find execution %d: %w", executionNum, err)
|
||||
}
|
||||
|
||||
err = c.canceler.Cancel(ctx, repo, execution)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to cancel execution: %w", err)
|
||||
}
|
||||
|
||||
// Write to the checks store, log and ignore on errors
|
||||
err = checks.Write(ctx, c.checkStore, execution, pipeline)
|
||||
if err != nil {
|
||||
log.Ctx(ctx).Warn().Err(err).Msg("could not update status check")
|
||||
}
|
||||
|
||||
return execution, nil
|
||||
}
|
||||
|
|
@ -1,106 +0,0 @@
|
|||
// Copyright 2023 Harness, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package execution
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
apiauth "github.com/harness/gitness/app/api/auth"
|
||||
"github.com/harness/gitness/app/auth"
|
||||
"github.com/harness/gitness/app/auth/authz"
|
||||
"github.com/harness/gitness/app/pipeline/canceler"
|
||||
"github.com/harness/gitness/app/pipeline/commit"
|
||||
"github.com/harness/gitness/app/pipeline/triggerer"
|
||||
"github.com/harness/gitness/app/services/refcache"
|
||||
"github.com/harness/gitness/app/store"
|
||||
"github.com/harness/gitness/store/database/dbtx"
|
||||
"github.com/harness/gitness/types"
|
||||
"github.com/harness/gitness/types/enum"
|
||||
)
|
||||
|
||||
type Controller struct {
|
||||
tx dbtx.Transactor
|
||||
authorizer authz.Authorizer
|
||||
executionStore store.ExecutionStore
|
||||
checkStore store.CheckStore
|
||||
canceler canceler.Canceler
|
||||
commitService commit.Service
|
||||
triggerer triggerer.Triggerer
|
||||
stageStore store.StageStore
|
||||
pipelineStore store.PipelineStore
|
||||
repoFinder refcache.RepoFinder
|
||||
}
|
||||
|
||||
func NewController(
|
||||
tx dbtx.Transactor,
|
||||
authorizer authz.Authorizer,
|
||||
executionStore store.ExecutionStore,
|
||||
checkStore store.CheckStore,
|
||||
canceler canceler.Canceler,
|
||||
commitService commit.Service,
|
||||
triggerer triggerer.Triggerer,
|
||||
stageStore store.StageStore,
|
||||
pipelineStore store.PipelineStore,
|
||||
repoFinder refcache.RepoFinder,
|
||||
) *Controller {
|
||||
return &Controller{
|
||||
tx: tx,
|
||||
authorizer: authorizer,
|
||||
executionStore: executionStore,
|
||||
checkStore: checkStore,
|
||||
canceler: canceler,
|
||||
commitService: commitService,
|
||||
triggerer: triggerer,
|
||||
stageStore: stageStore,
|
||||
pipelineStore: pipelineStore,
|
||||
repoFinder: repoFinder,
|
||||
}
|
||||
}
|
||||
|
||||
// getRepoCheckPipelineAccess fetches a repo, checks if the permission is allowed based on the repo state,
|
||||
// and checks if the current user has permission to access pipelines belong to it.
|
||||
//
|
||||
//nolint:unparam
|
||||
func (c *Controller) getRepoCheckPipelineAccess(
|
||||
ctx context.Context,
|
||||
session *auth.Session,
|
||||
repoRef string,
|
||||
pipelineIdentifier string,
|
||||
reqPermission enum.Permission,
|
||||
allowedRepoStates ...enum.RepoState,
|
||||
) (*types.RepositoryCore, error) {
|
||||
repo, err := c.repoFinder.FindByRef(ctx, repoRef)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to find repo by ref: %w", err)
|
||||
}
|
||||
|
||||
if err := apiauth.CheckRepoState(ctx, session, repo, reqPermission, allowedRepoStates...); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = apiauth.CheckPipeline(
|
||||
ctx,
|
||||
c.authorizer,
|
||||
session,
|
||||
repo.Path,
|
||||
pipelineIdentifier,
|
||||
reqPermission)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to authorize: %w", err)
|
||||
}
|
||||
|
||||
return repo, nil
|
||||
}
|
||||
|
|
@ -1,84 +0,0 @@
|
|||
// Copyright 2023 Harness, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package execution
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/harness/gitness/app/auth"
|
||||
"github.com/harness/gitness/app/pipeline/triggerer"
|
||||
"github.com/harness/gitness/types"
|
||||
"github.com/harness/gitness/types/enum"
|
||||
|
||||
"github.com/drone/go-scm/scm"
|
||||
)
|
||||
|
||||
func (c *Controller) Create(
|
||||
ctx context.Context,
|
||||
session *auth.Session,
|
||||
repoRef string,
|
||||
pipelineIdentifier string,
|
||||
branch string,
|
||||
) (*types.Execution, error) {
|
||||
repo, err := c.getRepoCheckPipelineAccess(ctx, session, repoRef, pipelineIdentifier, enum.PermissionPipelineExecute)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
pipeline, err := c.pipelineStore.FindByIdentifier(ctx, repo.ID, pipelineIdentifier)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to find pipeline: %w", err)
|
||||
}
|
||||
|
||||
// If the branch is empty, use the default branch specified in the pipeline.
|
||||
// It that is also empty, use the repo default branch.
|
||||
if branch == "" {
|
||||
branch = pipeline.DefaultBranch
|
||||
if branch == "" {
|
||||
branch = repo.DefaultBranch
|
||||
}
|
||||
}
|
||||
// expand the branch to a git reference.
|
||||
ref := scm.ExpandRef(branch, "refs/heads")
|
||||
|
||||
// Fetch the commit information from the commits service.
|
||||
commit, err := c.commitService.FindRef(ctx, repo, ref)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to fetch commit: %w", err)
|
||||
}
|
||||
|
||||
// Create manual hook for execution.
|
||||
hook := &triggerer.Hook{
|
||||
Trigger: session.Principal.UID, // who/what triggered the build, different from commit author
|
||||
AuthorLogin: commit.Author.Identity.Name,
|
||||
TriggeredBy: session.Principal.ID,
|
||||
AuthorName: commit.Author.Identity.Name,
|
||||
AuthorEmail: commit.Author.Identity.Email,
|
||||
Ref: ref,
|
||||
Message: commit.Message,
|
||||
Title: commit.Title,
|
||||
Before: commit.SHA.String(),
|
||||
After: commit.SHA.String(),
|
||||
Sender: session.Principal.UID,
|
||||
Source: branch,
|
||||
Target: branch,
|
||||
Params: map[string]string{},
|
||||
Timestamp: commit.Author.When.UnixMilli(),
|
||||
}
|
||||
|
||||
// Trigger the execution
|
||||
return c.triggerer.Trigger(ctx, pipeline, hook)
|
||||
}
|
||||
|
|
@ -1,54 +0,0 @@
|
|||
// Copyright 2023 Harness, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package execution
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/harness/gitness/app/auth"
|
||||
"github.com/harness/gitness/types/enum"
|
||||
)
|
||||
|
||||
func (c *Controller) Delete(
|
||||
ctx context.Context,
|
||||
session *auth.Session,
|
||||
repoRef string,
|
||||
pipelineIdentifier string,
|
||||
executionNum int64,
|
||||
) error {
|
||||
repo, err := c.getRepoCheckPipelineAccess(
|
||||
ctx,
|
||||
session,
|
||||
repoRef,
|
||||
pipelineIdentifier,
|
||||
enum.PermissionPipelineDelete,
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
pipeline, err := c.pipelineStore.FindByIdentifier(ctx, repo.ID, pipelineIdentifier)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to find pipeline: %w", err)
|
||||
}
|
||||
|
||||
err = c.executionStore.Delete(ctx, pipeline.ID, executionNum)
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not delete execution: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
@ -1,64 +0,0 @@
|
|||
// Copyright 2023 Harness, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package execution
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/harness/gitness/app/auth"
|
||||
"github.com/harness/gitness/types"
|
||||
"github.com/harness/gitness/types/enum"
|
||||
)
|
||||
|
||||
func (c *Controller) Find(
|
||||
ctx context.Context,
|
||||
session *auth.Session,
|
||||
repoRef string,
|
||||
pipelineIdentifier string,
|
||||
executionNum int64,
|
||||
) (*types.Execution, error) {
|
||||
repo, err := c.getRepoCheckPipelineAccess(
|
||||
ctx,
|
||||
session,
|
||||
repoRef,
|
||||
pipelineIdentifier,
|
||||
enum.PermissionPipelineView,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
pipeline, err := c.pipelineStore.FindByIdentifier(ctx, repo.ID, pipelineIdentifier)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to find pipeline: %w", err)
|
||||
}
|
||||
|
||||
execution, err := c.executionStore.FindByNumber(ctx, pipeline.ID, executionNum)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to find execution %d: %w", executionNum, err)
|
||||
}
|
||||
|
||||
stages, err := c.stageStore.ListWithSteps(ctx, execution.ID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not query stage information for execution %d: %w",
|
||||
executionNum, err)
|
||||
}
|
||||
|
||||
// Add stages information to the execution
|
||||
execution.Stages = stages
|
||||
|
||||
return execution, nil
|
||||
}
|
||||
|
|
@ -1,71 +0,0 @@
|
|||
// Copyright 2023 Harness, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package execution
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/harness/gitness/app/auth"
|
||||
"github.com/harness/gitness/store/database/dbtx"
|
||||
"github.com/harness/gitness/types"
|
||||
"github.com/harness/gitness/types/enum"
|
||||
)
|
||||
|
||||
func (c *Controller) List(
|
||||
ctx context.Context,
|
||||
session *auth.Session,
|
||||
repoRef string,
|
||||
pipelineIdentifier string,
|
||||
pagination types.Pagination,
|
||||
) ([]*types.Execution, int64, error) {
|
||||
repo, err := c.getRepoCheckPipelineAccess(
|
||||
ctx,
|
||||
session,
|
||||
repoRef,
|
||||
pipelineIdentifier,
|
||||
enum.PermissionPipelineView,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
pipeline, err := c.pipelineStore.FindByIdentifier(ctx, repo.ID, pipelineIdentifier)
|
||||
if err != nil {
|
||||
return nil, 0, fmt.Errorf("failed to find pipeline: %w", err)
|
||||
}
|
||||
|
||||
var count int64
|
||||
var executions []*types.Execution
|
||||
|
||||
err = c.tx.WithTx(ctx, func(ctx context.Context) (err error) {
|
||||
count, err = c.executionStore.Count(ctx, pipeline.ID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to count child executions: %w", err)
|
||||
}
|
||||
|
||||
executions, err = c.executionStore.List(ctx, pipeline.ID, pagination)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to list child executions: %w", err)
|
||||
}
|
||||
|
||||
return
|
||||
}, dbtx.TxDefaultReadOnly)
|
||||
if err != nil {
|
||||
return executions, count, fmt.Errorf("failed to fetch list: %w", err)
|
||||
}
|
||||
|
||||
return executions, count, nil
|
||||
}
|
||||
|
|
@ -1,48 +0,0 @@
|
|||
// Copyright 2023 Harness, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package execution
|
||||
|
||||
import (
|
||||
"github.com/harness/gitness/app/auth/authz"
|
||||
"github.com/harness/gitness/app/pipeline/canceler"
|
||||
"github.com/harness/gitness/app/pipeline/commit"
|
||||
"github.com/harness/gitness/app/pipeline/triggerer"
|
||||
"github.com/harness/gitness/app/services/refcache"
|
||||
"github.com/harness/gitness/app/store"
|
||||
"github.com/harness/gitness/store/database/dbtx"
|
||||
|
||||
"github.com/google/wire"
|
||||
)
|
||||
|
||||
// WireSet provides a wire set for this package.
|
||||
var WireSet = wire.NewSet(
|
||||
ProvideController,
|
||||
)
|
||||
|
||||
func ProvideController(
|
||||
tx dbtx.Transactor,
|
||||
authorizer authz.Authorizer,
|
||||
executionStore store.ExecutionStore,
|
||||
checkStore store.CheckStore,
|
||||
canceler canceler.Canceler,
|
||||
commitService commit.Service,
|
||||
triggerer triggerer.Triggerer,
|
||||
stageStore store.StageStore,
|
||||
pipelineStore store.PipelineStore,
|
||||
repoFinder refcache.RepoFinder,
|
||||
) *Controller {
|
||||
return NewController(tx, authorizer, executionStore, checkStore,
|
||||
canceler, commitService, triggerer, stageStore, pipelineStore, repoFinder)
|
||||
}
|
||||
|
|
@ -1,141 +0,0 @@
|
|||
// Copyright 2023 Harness, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package githook
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/harness/gitness/app/githook"
|
||||
"github.com/harness/gitness/git"
|
||||
"github.com/harness/gitness/git/hook"
|
||||
"github.com/harness/gitness/store"
|
||||
"github.com/harness/gitness/types"
|
||||
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
var _ hook.ClientFactory = (*ControllerClientFactory)(nil)
|
||||
var _ hook.Client = (*ControllerClient)(nil)
|
||||
|
||||
// ControllerClientFactory creates clients that directly call the controller to execute githooks.
|
||||
type ControllerClientFactory struct {
|
||||
githookCtrl *Controller
|
||||
git git.Interface
|
||||
}
|
||||
|
||||
func (f *ControllerClientFactory) NewClient(envVars map[string]string) (hook.Client, error) {
|
||||
payload, err := hook.LoadPayloadFromMap[githook.Payload](envVars)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to load payload from provided map of environment variables: %w", err)
|
||||
}
|
||||
|
||||
// ensure we return disabled message in case it's explicitly disabled
|
||||
if payload.Disabled {
|
||||
return hook.NewNoopClient([]string{"hook disabled"}), nil
|
||||
}
|
||||
|
||||
if err := payload.Validate(); err != nil {
|
||||
return nil, fmt.Errorf("payload validation failed: %w", err)
|
||||
}
|
||||
|
||||
return &ControllerClient{
|
||||
baseInput: githook.GetInputBaseFromPayload(payload),
|
||||
githookCtrl: f.githookCtrl,
|
||||
git: f.git,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// ControllerClient directly calls the controller to execute githooks.
|
||||
type ControllerClient struct {
|
||||
baseInput types.GithookInputBase
|
||||
githookCtrl *Controller
|
||||
git RestrictedGIT
|
||||
}
|
||||
|
||||
func (c *ControllerClient) PreReceive(
|
||||
ctx context.Context,
|
||||
in hook.PreReceiveInput,
|
||||
) (hook.Output, error) {
|
||||
log.Ctx(ctx).Debug().Int64("repo_id", c.baseInput.RepoID).Msg("calling pre-receive")
|
||||
|
||||
out, err := c.githookCtrl.PreReceive(
|
||||
ctx,
|
||||
c.git, // Harness doesn't require any custom git connector.
|
||||
nil, // TODO: update once githooks are auth protected
|
||||
types.GithookPreReceiveInput{
|
||||
GithookInputBase: c.baseInput,
|
||||
PreReceiveInput: in,
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
return hook.Output{}, translateControllerError(err)
|
||||
}
|
||||
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *ControllerClient) Update(
|
||||
ctx context.Context,
|
||||
in hook.UpdateInput,
|
||||
) (hook.Output, error) {
|
||||
log.Ctx(ctx).Debug().Int64("repo_id", c.baseInput.RepoID).Msg("calling update")
|
||||
|
||||
out, err := c.githookCtrl.Update(
|
||||
ctx,
|
||||
c.git, // Harness doesn't require any custom git connector.
|
||||
nil, // TODO: update once githooks are auth protected
|
||||
types.GithookUpdateInput{
|
||||
GithookInputBase: c.baseInput,
|
||||
UpdateInput: in,
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
return hook.Output{}, translateControllerError(err)
|
||||
}
|
||||
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *ControllerClient) PostReceive(
|
||||
ctx context.Context,
|
||||
in hook.PostReceiveInput,
|
||||
) (hook.Output, error) {
|
||||
log.Ctx(ctx).Debug().Int64("repo_id", c.baseInput.RepoID).Msg("calling post-receive")
|
||||
|
||||
out, err := c.githookCtrl.PostReceive(
|
||||
ctx,
|
||||
c.git, // Harness doesn't require any custom git connector.
|
||||
nil, // TODO: update once githooks are auth protected
|
||||
types.GithookPostReceiveInput{
|
||||
GithookInputBase: c.baseInput,
|
||||
PostReceiveInput: in,
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
return hook.Output{}, translateControllerError(err)
|
||||
}
|
||||
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func translateControllerError(err error) error {
|
||||
if errors.Is(err, store.ErrResourceNotFound) {
|
||||
return hook.ErrNotFound
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
|
@ -1,237 +0,0 @@
|
|||
// Copyright 2023 Harness, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package githook
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/harness/gitness/app/api/controller/limiter"
|
||||
"github.com/harness/gitness/app/api/usererror"
|
||||
"github.com/harness/gitness/app/auth"
|
||||
"github.com/harness/gitness/app/auth/authz"
|
||||
gitevents "github.com/harness/gitness/app/events/git"
|
||||
repoevents "github.com/harness/gitness/app/events/repo"
|
||||
"github.com/harness/gitness/app/services/protection"
|
||||
"github.com/harness/gitness/app/services/refcache"
|
||||
"github.com/harness/gitness/app/services/settings"
|
||||
"github.com/harness/gitness/app/services/usergroup"
|
||||
"github.com/harness/gitness/app/sse"
|
||||
"github.com/harness/gitness/app/store"
|
||||
"github.com/harness/gitness/app/url"
|
||||
"github.com/harness/gitness/audit"
|
||||
"github.com/harness/gitness/errors"
|
||||
"github.com/harness/gitness/git"
|
||||
"github.com/harness/gitness/git/api"
|
||||
"github.com/harness/gitness/git/hook"
|
||||
"github.com/harness/gitness/git/sha"
|
||||
"github.com/harness/gitness/types"
|
||||
"github.com/harness/gitness/types/enum"
|
||||
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
type Controller struct {
|
||||
authorizer authz.Authorizer
|
||||
principalStore store.PrincipalStore
|
||||
repoStore store.RepoStore
|
||||
repoFinder refcache.RepoFinder
|
||||
gitReporter *gitevents.Reporter
|
||||
repoReporter *repoevents.Reporter
|
||||
pullreqStore store.PullReqStore
|
||||
urlProvider url.Provider
|
||||
protectionManager *protection.Manager
|
||||
limiter limiter.ResourceLimiter
|
||||
settings *settings.Service
|
||||
preReceiveExtender PreReceiveExtender
|
||||
updateExtender UpdateExtender
|
||||
postReceiveExtender PostReceiveExtender
|
||||
sseStreamer sse.Streamer
|
||||
lfsStore store.LFSObjectStore
|
||||
auditService audit.Service
|
||||
userGroupService usergroup.Service
|
||||
}
|
||||
|
||||
func NewController(
|
||||
authorizer authz.Authorizer,
|
||||
principalStore store.PrincipalStore,
|
||||
repoStore store.RepoStore,
|
||||
repoFinder refcache.RepoFinder,
|
||||
gitReporter *gitevents.Reporter,
|
||||
repoReporter *repoevents.Reporter,
|
||||
pullreqStore store.PullReqStore,
|
||||
urlProvider url.Provider,
|
||||
protectionManager *protection.Manager,
|
||||
limiter limiter.ResourceLimiter,
|
||||
settings *settings.Service,
|
||||
preReceiveExtender PreReceiveExtender,
|
||||
updateExtender UpdateExtender,
|
||||
postReceiveExtender PostReceiveExtender,
|
||||
sseStreamer sse.Streamer,
|
||||
lfsStore store.LFSObjectStore,
|
||||
auditService audit.Service,
|
||||
userGroupService usergroup.Service,
|
||||
) *Controller {
|
||||
return &Controller{
|
||||
authorizer: authorizer,
|
||||
principalStore: principalStore,
|
||||
repoStore: repoStore,
|
||||
repoFinder: repoFinder,
|
||||
gitReporter: gitReporter,
|
||||
repoReporter: repoReporter,
|
||||
pullreqStore: pullreqStore,
|
||||
urlProvider: urlProvider,
|
||||
protectionManager: protectionManager,
|
||||
limiter: limiter,
|
||||
settings: settings,
|
||||
preReceiveExtender: preReceiveExtender,
|
||||
updateExtender: updateExtender,
|
||||
postReceiveExtender: postReceiveExtender,
|
||||
sseStreamer: sseStreamer,
|
||||
lfsStore: lfsStore,
|
||||
auditService: auditService,
|
||||
userGroupService: userGroupService,
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Controller) getRepoCheckAccess(
|
||||
ctx context.Context,
|
||||
_ *auth.Session,
|
||||
repoID int64,
|
||||
_ enum.Permission,
|
||||
) (*types.RepositoryCore, error) {
|
||||
if repoID < 1 {
|
||||
return nil, usererror.BadRequest("A valid repository reference must be provided.")
|
||||
}
|
||||
|
||||
repo, err := c.repoFinder.FindByID(ctx, repoID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to find repo with id %d: %w", repoID, err)
|
||||
}
|
||||
// repo state check is done in pre-receive.
|
||||
|
||||
// TODO: execute permission check. block anything but Harness service?
|
||||
|
||||
return repo, nil
|
||||
}
|
||||
|
||||
// GetBaseSHAForScanningChanges returns the commit sha to which the new sha of the reference
|
||||
// should be compared against when scanning incoming changes.
|
||||
// NOTE: If no such a sha exists, then (sha.None, false, nil) is returned.
|
||||
// This will happen in case the default branch doesn't exist yet.
|
||||
func GetBaseSHAForScanningChanges(
|
||||
ctx context.Context,
|
||||
rgit RestrictedGIT,
|
||||
repo *types.RepositoryCore,
|
||||
env hook.Environment,
|
||||
refUpdates []hook.ReferenceUpdate,
|
||||
findBaseFor hook.ReferenceUpdate,
|
||||
) (sha.SHA, bool, error) {
|
||||
// always return old SHA of ref if possible (even if ref was deleted, that's on the caller)
|
||||
if !findBaseFor.Old.IsNil() {
|
||||
return findBaseFor.Old, true, nil
|
||||
}
|
||||
|
||||
// reference is just being created.
|
||||
// For now we use default branch as a fallback (can be optimized to most recent commit on reference that exists)
|
||||
dfltBranchFullRef := api.BranchPrefix + repo.DefaultBranch
|
||||
for _, refUpdate := range refUpdates {
|
||||
if refUpdate.Ref != dfltBranchFullRef {
|
||||
continue
|
||||
}
|
||||
|
||||
// default branch is being updated as part of push - make sure we use OLD default branch sha for comparison
|
||||
if !refUpdate.Old.IsNil() {
|
||||
return refUpdate.Old, true, nil
|
||||
}
|
||||
|
||||
// default branch is being created - no fallback available
|
||||
return sha.None, false, nil
|
||||
}
|
||||
|
||||
// read default branch from git
|
||||
dfltBranchOut, err := rgit.GetBranch(ctx, &git.GetBranchParams{
|
||||
ReadParams: git.ReadParams{
|
||||
RepoUID: repo.GitUID,
|
||||
AlternateObjectDirs: env.AlternateObjectDirs,
|
||||
},
|
||||
BranchName: repo.DefaultBranch,
|
||||
})
|
||||
if errors.IsNotFound(err) {
|
||||
// this happens for empty repo's where the default branch wasn't created yet.
|
||||
return sha.None, false, nil
|
||||
}
|
||||
if err != nil {
|
||||
return sha.None, false, fmt.Errorf("failed to get default branch from git: %w", err)
|
||||
}
|
||||
|
||||
return dfltBranchOut.Branch.SHA, true, nil
|
||||
}
|
||||
|
||||
func isForcePush(
|
||||
ctx context.Context,
|
||||
rgit RestrictedGIT,
|
||||
gitUID string,
|
||||
alternateObjectDirs []string,
|
||||
refUpdate hook.ReferenceUpdate,
|
||||
) (bool, error) {
|
||||
if refUpdate.Old.IsNil() || refUpdate.New.IsNil() {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
if isTag(refUpdate.Ref) {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
result, err := rgit.IsAncestor(ctx, git.IsAncestorParams{
|
||||
ReadParams: git.ReadParams{
|
||||
RepoUID: gitUID,
|
||||
AlternateObjectDirs: alternateObjectDirs,
|
||||
},
|
||||
AncestorCommitSHA: refUpdate.Old,
|
||||
DescendantCommitSHA: refUpdate.New,
|
||||
})
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
return !result.Ancestor, nil
|
||||
}
|
||||
|
||||
func logOutputFor(ctx context.Context, hookName string, output hook.Output) {
|
||||
event := log.Ctx(ctx).Info()
|
||||
|
||||
if output.Error != nil {
|
||||
event = event.Str("output.error", *output.Error)
|
||||
}
|
||||
|
||||
if len(output.Messages) > 0 {
|
||||
filteredMsgs := make([]string, 0, len(output.Messages)/2+1)
|
||||
for _, msg := range output.Messages {
|
||||
if msg == "" {
|
||||
continue
|
||||
}
|
||||
filteredMsgs = append(filteredMsgs, msg)
|
||||
}
|
||||
|
||||
const maxMessageLines = 16
|
||||
if len(filteredMsgs) > maxMessageLines {
|
||||
filteredMsgs = append(filteredMsgs[:maxMessageLines], fmt.Sprintf("... %d more", len(filteredMsgs)-maxMessageLines))
|
||||
}
|
||||
event = event.Strs("output.messages", filteredMsgs)
|
||||
}
|
||||
|
||||
event.Msgf("%s hook output", hookName)
|
||||
}
|
||||
|
|
@ -1,110 +0,0 @@
|
|||
// Copyright 2023 Harness, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package githook
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/harness/gitness/app/auth"
|
||||
"github.com/harness/gitness/git/hook"
|
||||
"github.com/harness/gitness/types"
|
||||
)
|
||||
|
||||
type PreReceiveExtender interface {
|
||||
Extend(
|
||||
context.Context,
|
||||
RestrictedGIT,
|
||||
*auth.Session,
|
||||
*types.RepositoryCore,
|
||||
types.GithookPreReceiveInput,
|
||||
*hook.Output,
|
||||
) error
|
||||
}
|
||||
|
||||
type UpdateExtender interface {
|
||||
Extend(
|
||||
context.Context,
|
||||
RestrictedGIT,
|
||||
*auth.Session,
|
||||
*types.RepositoryCore,
|
||||
types.GithookUpdateInput,
|
||||
*hook.Output,
|
||||
) error
|
||||
}
|
||||
|
||||
type PostReceiveExtender interface {
|
||||
Extend(
|
||||
context.Context,
|
||||
RestrictedGIT,
|
||||
*auth.Session,
|
||||
*types.RepositoryCore,
|
||||
types.GithookPostReceiveInput,
|
||||
*hook.Output,
|
||||
) error
|
||||
}
|
||||
|
||||
type NoOpPreReceiveExtender struct {
|
||||
}
|
||||
|
||||
func NewPreReceiveExtender() PreReceiveExtender {
|
||||
return NoOpPreReceiveExtender{}
|
||||
}
|
||||
|
||||
func (NoOpPreReceiveExtender) Extend(
|
||||
context.Context,
|
||||
RestrictedGIT,
|
||||
*auth.Session,
|
||||
*types.RepositoryCore,
|
||||
types.GithookPreReceiveInput,
|
||||
*hook.Output,
|
||||
) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
type NoOpUpdateExtender struct {
|
||||
}
|
||||
|
||||
func NewUpdateExtender() UpdateExtender {
|
||||
return NoOpUpdateExtender{}
|
||||
}
|
||||
|
||||
func (NoOpUpdateExtender) Extend(
|
||||
context.Context,
|
||||
RestrictedGIT,
|
||||
*auth.Session,
|
||||
*types.RepositoryCore,
|
||||
types.GithookUpdateInput,
|
||||
*hook.Output,
|
||||
) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
type NoOpPostReceiveExtender struct {
|
||||
}
|
||||
|
||||
func NewPostReceiveExtender() PostReceiveExtender {
|
||||
return NoOpPostReceiveExtender{}
|
||||
}
|
||||
|
||||
func (NoOpPostReceiveExtender) Extend(
|
||||
context.Context,
|
||||
RestrictedGIT,
|
||||
*auth.Session,
|
||||
*types.RepositoryCore,
|
||||
types.GithookPostReceiveInput,
|
||||
*hook.Output,
|
||||
) error {
|
||||
return nil
|
||||
}
|
||||
|
|
@ -1,40 +0,0 @@
|
|||
// Copyright 2023 Harness, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package githook
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/harness/gitness/git"
|
||||
"github.com/harness/gitness/git/api"
|
||||
)
|
||||
|
||||
// RestrictedGIT is a git client that is restricted to a subset of operations of git.Interface
|
||||
// which can be executed on quarantine data that is part of git-hooks (e.g. pre-receive, update, ..)
|
||||
// and don't alter the repo (so only read operations).
|
||||
// NOTE: While it doesn't apply to all git-hooks (e.g. post-receive), we still use the interface across the board
|
||||
// to "soft enforce" no write operations being executed as part of githooks.
|
||||
type RestrictedGIT interface {
|
||||
IsAncestor(ctx context.Context, params git.IsAncestorParams) (git.IsAncestorOutput, error)
|
||||
ScanSecrets(ctx context.Context, param *git.ScanSecretsParams) (*git.ScanSecretsOutput, error)
|
||||
GetBranch(ctx context.Context, params *git.GetBranchParams) (*git.GetBranchOutput, error)
|
||||
Diff(ctx context.Context, in *git.DiffParams, files ...api.FileDiffRequest) (<-chan *git.FileDiff, <-chan error)
|
||||
GetBlob(ctx context.Context, params *git.GetBlobParams) (*git.GetBlobOutput, error)
|
||||
ProcessPreReceiveObjects(
|
||||
ctx context.Context,
|
||||
params git.ProcessPreReceiveObjectsParams,
|
||||
) (git.ProcessPreReceiveObjectsOutput, error)
|
||||
MergeBase(ctx context.Context, params git.MergeBaseParams) (git.MergeBaseOutput, error)
|
||||
}
|
||||
|
|
@ -1,605 +0,0 @@
|
|||
// Copyright 2023 Harness, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package githook
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"slices"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/harness/gitness/app/api/usererror"
|
||||
"github.com/harness/gitness/app/auth"
|
||||
"github.com/harness/gitness/app/bootstrap"
|
||||
gitevents "github.com/harness/gitness/app/events/git"
|
||||
repoevents "github.com/harness/gitness/app/events/repo"
|
||||
"github.com/harness/gitness/app/paths"
|
||||
"github.com/harness/gitness/audit"
|
||||
"github.com/harness/gitness/errors"
|
||||
"github.com/harness/gitness/git"
|
||||
gitapi "github.com/harness/gitness/git/api"
|
||||
gitenum "github.com/harness/gitness/git/enum"
|
||||
"github.com/harness/gitness/git/hook"
|
||||
"github.com/harness/gitness/git/sha"
|
||||
"github.com/harness/gitness/types"
|
||||
"github.com/harness/gitness/types/enum"
|
||||
|
||||
"github.com/gotidy/ptr"
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
const (
|
||||
// gitReferenceNamePrefixBranch is the prefix of references of type branch.
|
||||
gitReferenceNamePrefixBranch = "refs/heads/"
|
||||
|
||||
// gitReferenceNamePrefixTag is the prefix of references of type tag.
|
||||
gitReferenceNamePrefixTag = "refs/tags/"
|
||||
|
||||
// gitReferenceNamePrefixTag is the prefix of pull req references.
|
||||
gitReferenceNamePullReq = "refs/pullreq/"
|
||||
)
|
||||
|
||||
// refForcePushMap stores branch refs that were force pushed.
|
||||
type refForcePushMap map[string]struct{}
|
||||
|
||||
// PostReceive executes the post-receive hook for a git repository.
|
||||
func (c *Controller) PostReceive(
|
||||
ctx context.Context,
|
||||
rgit RestrictedGIT,
|
||||
session *auth.Session,
|
||||
in types.GithookPostReceiveInput,
|
||||
) (hook.Output, error) {
|
||||
repoCore, err := c.getRepoCheckAccess(ctx, session, in.RepoID, enum.PermissionRepoPush)
|
||||
if err != nil {
|
||||
return hook.Output{}, err
|
||||
}
|
||||
|
||||
repo, err := c.repoStore.Find(ctx, repoCore.ID)
|
||||
if err != nil {
|
||||
return hook.Output{}, err
|
||||
}
|
||||
|
||||
// create output object and have following messages fill its messages
|
||||
out := hook.Output{}
|
||||
defer func() {
|
||||
logOutputFor(ctx, "post-receive", out)
|
||||
}()
|
||||
|
||||
// update default branch based on ref update info on empty repos.
|
||||
// as the branch could be different than the configured default value.
|
||||
c.handleEmptyRepoPush(ctx, repo, in.PostReceiveInput, &out)
|
||||
|
||||
// always update last git push time - best effort
|
||||
c.updateLastGITPushTime(ctx, repo)
|
||||
|
||||
// report ref events if repo is in an active state - best effort
|
||||
forcePushStatus := make(refForcePushMap)
|
||||
if repo.State == enum.RepoStateActive {
|
||||
forcePushStatus = c.reportReferenceEvents(ctx, rgit, repo, in.PrincipalID, in.PostReceiveInput)
|
||||
}
|
||||
|
||||
// handle branch updates related to PRs - best effort
|
||||
c.handlePRMessaging(ctx, rgit, repo, in.PostReceiveInput, &out)
|
||||
|
||||
err = c.postReceiveExtender.Extend(ctx, rgit, session, repo.Core(), in, &out)
|
||||
if err != nil {
|
||||
return hook.Output{}, fmt.Errorf("failed to extend post-receive hook: %w", err)
|
||||
}
|
||||
|
||||
c.logForcePush(ctx, repo, in.PrincipalID, in.RefUpdates, forcePushStatus)
|
||||
|
||||
c.repoReporter.Pushed(ctx, &repoevents.PushedPayload{
|
||||
Base: repoevents.Base{
|
||||
RepoID: in.RepoID,
|
||||
PrincipalID: in.PrincipalID,
|
||||
},
|
||||
})
|
||||
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// reportReferenceEvents is reporting reference events to the event system.
|
||||
// NOTE: keep best effort for now as it doesn't change the outcome of the git operation.
|
||||
// TODO: in the future we might want to think about propagating errors so user is aware of events not being triggered.
|
||||
func (c *Controller) reportReferenceEvents(
|
||||
ctx context.Context,
|
||||
rgit RestrictedGIT,
|
||||
repo *types.Repository,
|
||||
principalID int64,
|
||||
in hook.PostReceiveInput,
|
||||
) refForcePushMap {
|
||||
forcePushStatus := make(refForcePushMap)
|
||||
|
||||
for _, refUpdate := range in.RefUpdates {
|
||||
switch {
|
||||
case strings.HasPrefix(refUpdate.Ref, gitReferenceNamePrefixBranch):
|
||||
if forced := c.reportBranchEvent(ctx, rgit, repo, principalID, in.Environment, refUpdate); forced {
|
||||
forcePushStatus[refUpdate.Ref] = struct{}{}
|
||||
}
|
||||
case strings.HasPrefix(refUpdate.Ref, gitReferenceNamePrefixTag):
|
||||
c.reportTagEvent(ctx, repo, principalID, refUpdate)
|
||||
default:
|
||||
// Ignore any other references in post-receive
|
||||
}
|
||||
}
|
||||
|
||||
return forcePushStatus
|
||||
}
|
||||
|
||||
func (c *Controller) reportBranchEvent(
|
||||
ctx context.Context,
|
||||
rgit RestrictedGIT,
|
||||
repo *types.Repository,
|
||||
principalID int64,
|
||||
env hook.Environment,
|
||||
branchUpdate hook.ReferenceUpdate,
|
||||
) bool {
|
||||
var forced bool
|
||||
|
||||
switch {
|
||||
case branchUpdate.Old.IsNil():
|
||||
payload := &gitevents.BranchCreatedPayload{
|
||||
RepoID: repo.ID,
|
||||
PrincipalID: principalID,
|
||||
Ref: branchUpdate.Ref,
|
||||
SHA: branchUpdate.New.String(),
|
||||
}
|
||||
|
||||
c.gitReporter.BranchCreated(ctx, payload)
|
||||
|
||||
c.sseStreamer.Publish(ctx, repo.ParentID, enum.SSETypeBranchCreated, payload)
|
||||
|
||||
case branchUpdate.New.IsNil():
|
||||
payload := &gitevents.BranchDeletedPayload{
|
||||
RepoID: repo.ID,
|
||||
PrincipalID: principalID,
|
||||
Ref: branchUpdate.Ref,
|
||||
SHA: branchUpdate.Old.String(),
|
||||
}
|
||||
|
||||
c.gitReporter.BranchDeleted(ctx, payload)
|
||||
|
||||
c.sseStreamer.Publish(ctx, repo.ParentID, enum.SSETypeBranchDeleted, payload)
|
||||
|
||||
default:
|
||||
// A force update event might trigger some additional operations that aren't required
|
||||
// for ordinary updates (force pushes alter the commit history of a branch).
|
||||
var err error
|
||||
forced, err = isForcePush(ctx, rgit, repo.GitUID, env.AlternateObjectDirs, branchUpdate)
|
||||
if err != nil {
|
||||
// In case of an error consider this a forced update. In post-update the branch has already been updated,
|
||||
// so there's less harm in declaring the update as forced.
|
||||
forced = true
|
||||
log.Ctx(ctx).Warn().Err(err).
|
||||
Str("ref", branchUpdate.Ref).
|
||||
Msg("failed to check ancestor")
|
||||
}
|
||||
|
||||
payload := &gitevents.BranchUpdatedPayload{
|
||||
RepoID: repo.ID,
|
||||
PrincipalID: principalID,
|
||||
Ref: branchUpdate.Ref,
|
||||
OldSHA: branchUpdate.Old.String(),
|
||||
NewSHA: branchUpdate.New.String(),
|
||||
Forced: forced,
|
||||
}
|
||||
|
||||
c.gitReporter.BranchUpdated(ctx, payload)
|
||||
|
||||
c.sseStreamer.Publish(ctx, repo.ParentID, enum.SSETypeBranchUpdated, payload)
|
||||
}
|
||||
|
||||
return forced
|
||||
}
|
||||
|
||||
func (c *Controller) reportTagEvent(
|
||||
ctx context.Context,
|
||||
repo *types.Repository,
|
||||
principalID int64,
|
||||
tagUpdate hook.ReferenceUpdate,
|
||||
) {
|
||||
switch {
|
||||
case tagUpdate.Old.IsNil():
|
||||
payload := &gitevents.TagCreatedPayload{
|
||||
RepoID: repo.ID,
|
||||
PrincipalID: principalID,
|
||||
Ref: tagUpdate.Ref,
|
||||
SHA: tagUpdate.New.String(),
|
||||
}
|
||||
|
||||
c.gitReporter.TagCreated(ctx, payload)
|
||||
|
||||
c.sseStreamer.Publish(ctx, repo.ParentID, enum.SSETypeTagCreated, payload)
|
||||
|
||||
case tagUpdate.New.IsNil():
|
||||
payload := &gitevents.TagDeletedPayload{
|
||||
RepoID: repo.ID,
|
||||
PrincipalID: principalID,
|
||||
Ref: tagUpdate.Ref,
|
||||
SHA: tagUpdate.Old.String(),
|
||||
}
|
||||
|
||||
c.gitReporter.TagDeleted(ctx, payload)
|
||||
|
||||
c.sseStreamer.Publish(ctx, repo.ParentID, enum.SSETypeTagDeleted, payload)
|
||||
|
||||
default:
|
||||
payload := &gitevents.TagUpdatedPayload{
|
||||
RepoID: repo.ID,
|
||||
PrincipalID: principalID,
|
||||
Ref: tagUpdate.Ref,
|
||||
OldSHA: tagUpdate.Old.String(),
|
||||
NewSHA: tagUpdate.New.String(),
|
||||
// tags can only be force updated!
|
||||
Forced: true,
|
||||
}
|
||||
|
||||
c.gitReporter.TagUpdated(ctx, payload)
|
||||
|
||||
c.sseStreamer.Publish(ctx, repo.ParentID, enum.SSETypeTagUpdated, payload)
|
||||
}
|
||||
}
|
||||
|
||||
// handlePRMessaging checks any single branch push for pr information and returns an according response if needed.
|
||||
// TODO: If it is a new branch, or an update on a branch without any PR, it also sends out an SSE for pr creation.
|
||||
func (c *Controller) handlePRMessaging(
|
||||
ctx context.Context,
|
||||
rgit RestrictedGIT,
|
||||
sourceRepo *types.Repository,
|
||||
in hook.PostReceiveInput,
|
||||
out *hook.Output,
|
||||
) {
|
||||
// skip anything that was a batch push / isn't branch related / isn't updating/creating a branch.
|
||||
if len(in.RefUpdates) != 1 ||
|
||||
!strings.HasPrefix(in.RefUpdates[0].Ref, gitReferenceNamePrefixBranch) ||
|
||||
in.RefUpdates[0].New.IsNil() {
|
||||
return
|
||||
}
|
||||
|
||||
// for now we only care about first branch that was pushed.
|
||||
refUpdate := in.RefUpdates[0]
|
||||
|
||||
branchName := refUpdate.Ref[len(gitReferenceNamePrefixBranch):]
|
||||
newSHA := refUpdate.New
|
||||
|
||||
c.suggestPullRequest(ctx, rgit, sourceRepo, branchName, newSHA, out)
|
||||
|
||||
// TODO: store latest pushed branch for user in cache and send out SSE
|
||||
}
|
||||
|
||||
func (c *Controller) suggestPullRequest(
|
||||
ctx context.Context,
|
||||
rgit RestrictedGIT,
|
||||
sourceRepo *types.Repository,
|
||||
branchName string,
|
||||
newSHA sha.SHA,
|
||||
out *hook.Output,
|
||||
) {
|
||||
// Find the most recent few open PRs created from this branch.
|
||||
prs, err := c.pullreqStore.List(ctx, &types.PullReqFilter{
|
||||
Page: 1,
|
||||
Size: 10,
|
||||
SourceRepoID: sourceRepo.ID,
|
||||
SourceBranch: branchName,
|
||||
// we only care about open PRs - merged/closed will lead to "create new PR" message
|
||||
States: []enum.PullReqState{enum.PullReqStateOpen},
|
||||
Order: enum.OrderDesc,
|
||||
Sort: enum.PullReqSortCreated,
|
||||
// don't care about the PR description, omit it from the response
|
||||
ExcludeDescription: true,
|
||||
})
|
||||
if err != nil {
|
||||
log.Ctx(ctx).Warn().Err(err).Msgf(
|
||||
"failed to find pullrequests for branch '%s' originating from repo '%s'",
|
||||
branchName,
|
||||
sourceRepo.Path,
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
slices.Reverse(prs) // Use ascending order for message output.
|
||||
|
||||
// For already existing PRs, check if the merge base is still unique and if there are PR with non-unique merge base
|
||||
// print them to users terminal to inform about pending closure.
|
||||
var prsNonUniqueMergeBase []*types.PullReq
|
||||
for _, pr := range prs {
|
||||
if pr.SourceRepoID == nil || *pr.SourceRepoID != pr.TargetRepoID {
|
||||
continue
|
||||
}
|
||||
|
||||
var targetBranch string
|
||||
targetBranch, err = git.GetRefPath(pr.TargetBranch, gitenum.RefTypeBranch)
|
||||
if err != nil {
|
||||
log.Ctx(ctx).Warn().Err(err).Msgf(
|
||||
"failed to create target reference from target branch'%s' originating from repo '%s'",
|
||||
pr.TargetBranch,
|
||||
sourceRepo.Path,
|
||||
)
|
||||
continue
|
||||
}
|
||||
|
||||
_, err = rgit.MergeBase(ctx, git.MergeBaseParams{
|
||||
ReadParams: git.ReadParams{RepoUID: sourceRepo.GitUID},
|
||||
Ref1: targetBranch,
|
||||
Ref2: newSHA.String(),
|
||||
})
|
||||
if errors.IsInvalidArgument(err) || gitapi.IsUnrelatedHistoriesError(err) {
|
||||
prsNonUniqueMergeBase = append(prsNonUniqueMergeBase, pr)
|
||||
continue
|
||||
}
|
||||
if err != nil {
|
||||
log.Ctx(ctx).Warn().Err(err).Msgf(
|
||||
"failed to find merge base for PR #%d originating from repo '%s'",
|
||||
pr.Number,
|
||||
sourceRepo.Path,
|
||||
)
|
||||
continue
|
||||
}
|
||||
}
|
||||
msgs, err := c.getNonUniqueMergeBasePRsMessages(ctx, sourceRepo, branchName, prsNonUniqueMergeBase)
|
||||
if err != nil {
|
||||
log.Ctx(ctx).Warn().Err(err).Msg("failed to get messages for open pull request")
|
||||
return
|
||||
}
|
||||
if len(msgs) > 0 {
|
||||
out.Messages = append(out.Messages, msgs...)
|
||||
return
|
||||
}
|
||||
|
||||
// For already existing PRs, print them to users terminal for easier access.
|
||||
msgs, err = c.getOpenPRsMessages(ctx, sourceRepo, branchName, prs)
|
||||
if err != nil {
|
||||
log.Ctx(ctx).Warn().Err(err).Msg("failed to get messages for open pull request")
|
||||
return
|
||||
}
|
||||
if len(msgs) > 0 {
|
||||
out.Messages = append(out.Messages, msgs...)
|
||||
return
|
||||
}
|
||||
|
||||
if branchName == sourceRepo.DefaultBranch {
|
||||
// Don't suggest a pull request if this is a push to the default branch.
|
||||
return
|
||||
}
|
||||
|
||||
// This is a new PR!
|
||||
out.Messages = append(out.Messages,
|
||||
fmt.Sprintf("Create a pull request for %q by visiting:", branchName),
|
||||
" "+c.urlProvider.GenerateUICompareURL(ctx, sourceRepo.Path, sourceRepo.DefaultBranch, branchName),
|
||||
)
|
||||
}
|
||||
|
||||
func (c *Controller) getOpenPRsMessages(
|
||||
ctx context.Context,
|
||||
sourceRepo *types.Repository,
|
||||
branchName string,
|
||||
prs []*types.PullReq,
|
||||
) ([]string, error) {
|
||||
if len(prs) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
msgs := make([]string, 0, 2*len(prs)+1)
|
||||
|
||||
if len(prs) == 1 {
|
||||
msgs = append(msgs, fmt.Sprintf("Branch %q has an open PR:", branchName))
|
||||
} else {
|
||||
msgs = append(msgs, fmt.Sprintf("Branch %q has open PRs:", branchName))
|
||||
}
|
||||
|
||||
msgs, err := c.appendPRs(ctx, prs, sourceRepo, msgs)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to append PRs: %w", err)
|
||||
}
|
||||
|
||||
return msgs, nil
|
||||
}
|
||||
|
||||
func (c *Controller) getNonUniqueMergeBasePRsMessages(
|
||||
ctx context.Context,
|
||||
sourceRepo *types.Repository,
|
||||
branchName string,
|
||||
prs []*types.PullReq,
|
||||
) ([]string, error) {
|
||||
if len(prs) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
msgs := make([]string, 0, 2*len(prs)+1)
|
||||
|
||||
if len(prs) == 1 {
|
||||
msgs = append(msgs,
|
||||
fmt.Sprintf("Branch %q has an open PR that would be closed because non-unique merge base:", branchName))
|
||||
} else {
|
||||
msgs = append(msgs,
|
||||
fmt.Sprintf("Branch %q has open PRs that would be closed because non-unique merge base:", branchName))
|
||||
}
|
||||
|
||||
msgs, err := c.appendPRs(ctx, prs, sourceRepo, msgs)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to append PRs: %w", err)
|
||||
}
|
||||
|
||||
return msgs, nil
|
||||
}
|
||||
|
||||
func (c *Controller) appendPRs(
|
||||
ctx context.Context,
|
||||
prs []*types.PullReq,
|
||||
sourceRepo *types.Repository,
|
||||
msgs []string,
|
||||
) ([]string, error) {
|
||||
for _, pr := range prs {
|
||||
path := sourceRepo.Path
|
||||
if pr.TargetRepoID != *pr.SourceRepoID {
|
||||
targetRepo, err := c.repoFinder.FindByID(ctx, pr.TargetRepoID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to find target repo by ID: %w", err)
|
||||
}
|
||||
|
||||
path = targetRepo.Path
|
||||
}
|
||||
|
||||
msgs = append(msgs, fmt.Sprintf(" (#%d) %s", pr.Number, pr.Title))
|
||||
msgs = append(msgs, " "+c.urlProvider.GenerateUIPRURL(ctx, path, pr.Number))
|
||||
}
|
||||
|
||||
return msgs, nil
|
||||
}
|
||||
|
||||
// handleEmptyRepoPush updates repo default branch on empty repos if push contains branches.
|
||||
func (c *Controller) handleEmptyRepoPush(
|
||||
ctx context.Context,
|
||||
repo *types.Repository,
|
||||
in hook.PostReceiveInput,
|
||||
out *hook.Output,
|
||||
) {
|
||||
if !repo.IsEmpty {
|
||||
return
|
||||
}
|
||||
|
||||
var newDefaultBranch string
|
||||
// update default branch if corresponding branch does not exist
|
||||
for _, refUpdate := range in.RefUpdates {
|
||||
if strings.HasPrefix(refUpdate.Ref, gitReferenceNamePrefixBranch) && !refUpdate.New.IsNil() {
|
||||
branchName := refUpdate.Ref[len(gitReferenceNamePrefixBranch):]
|
||||
if branchName == repo.DefaultBranch {
|
||||
newDefaultBranch = branchName
|
||||
break
|
||||
}
|
||||
// use the first pushed branch if default branch is not present.
|
||||
if newDefaultBranch == "" {
|
||||
newDefaultBranch = branchName
|
||||
}
|
||||
}
|
||||
}
|
||||
if newDefaultBranch == "" {
|
||||
out.Error = ptr.String(usererror.ErrEmptyRepoNeedsBranch.Error())
|
||||
return
|
||||
}
|
||||
|
||||
oldName := repo.DefaultBranch
|
||||
var err error
|
||||
repo, err = c.repoStore.UpdateOptLock(ctx, repo, func(r *types.Repository) error {
|
||||
r.IsEmpty = false
|
||||
r.DefaultBranch = newDefaultBranch
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
log.Ctx(ctx).Warn().Err(err).Msgf("failed to update the repo default branch to %s and is_empty to false",
|
||||
newDefaultBranch)
|
||||
return
|
||||
}
|
||||
|
||||
c.repoFinder.MarkChanged(ctx, repo.Core())
|
||||
|
||||
if repo.DefaultBranch != oldName {
|
||||
c.repoReporter.DefaultBranchUpdated(ctx, &repoevents.DefaultBranchUpdatedPayload{
|
||||
Base: repoevents.Base{
|
||||
RepoID: repo.ID,
|
||||
PrincipalID: bootstrap.NewSystemServiceSession().Principal.ID,
|
||||
},
|
||||
OldName: oldName,
|
||||
NewName: repo.DefaultBranch,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// updateLastGITPushTime updates the repo's last git push time.
|
||||
func (c *Controller) updateLastGITPushTime(
|
||||
ctx context.Context,
|
||||
repo *types.Repository,
|
||||
) {
|
||||
newRepo, err := c.repoStore.UpdateOptLock(ctx, repo, func(r *types.Repository) error {
|
||||
r.LastGITPush = time.Now().UnixMilli()
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
log.Ctx(ctx).Warn().Err(err).Msgf("failed to update last git push time for repo %q", repo.Path)
|
||||
return
|
||||
}
|
||||
|
||||
*repo = *newRepo
|
||||
}
|
||||
|
||||
// logForcePush detects and logs force pushes to the default branch.
|
||||
func (c *Controller) logForcePush(
|
||||
ctx context.Context,
|
||||
repo *types.Repository,
|
||||
principalID int64,
|
||||
refUpdates []hook.ReferenceUpdate,
|
||||
forcePushStatus refForcePushMap,
|
||||
) {
|
||||
if repo.DefaultBranch == "" {
|
||||
return
|
||||
}
|
||||
|
||||
defaultBranchRef := gitReferenceNamePrefixBranch + repo.DefaultBranch
|
||||
|
||||
_, exists := forcePushStatus[defaultBranchRef]
|
||||
if !exists {
|
||||
return
|
||||
}
|
||||
|
||||
var defaultBranchUpdate *hook.ReferenceUpdate
|
||||
for i := range refUpdates {
|
||||
if refUpdates[i].Ref == defaultBranchRef && !refUpdates[i].New.IsNil() {
|
||||
defaultBranchUpdate = &refUpdates[i]
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if defaultBranchUpdate == nil {
|
||||
return
|
||||
}
|
||||
|
||||
principal, err := c.principalStore.Find(ctx, principalID)
|
||||
if err != nil {
|
||||
log.Ctx(ctx).Warn().Err(err).Msg("failed to find principal who force pushed to default branch")
|
||||
return
|
||||
}
|
||||
|
||||
err = c.auditService.Log(ctx,
|
||||
*principal,
|
||||
audit.NewResource(
|
||||
audit.ResourceTypeRepository,
|
||||
repo.Identifier,
|
||||
audit.RepoPath,
|
||||
repo.Path,
|
||||
audit.BypassedResourceType,
|
||||
audit.BypassedResourceTypeCommit,
|
||||
audit.ResourceName,
|
||||
fmt.Sprintf(
|
||||
audit.BypassSHALabelFormat,
|
||||
repo.DefaultBranch,
|
||||
defaultBranchUpdate.New.String()[0:6],
|
||||
),
|
||||
),
|
||||
audit.ActionForcePush,
|
||||
paths.Parent(repo.Path),
|
||||
audit.WithOldObject(audit.CommitObject{
|
||||
CommitSHA: defaultBranchUpdate.Old.String(),
|
||||
RepoPath: repo.Path,
|
||||
}),
|
||||
audit.WithNewObject(audit.CommitObject{
|
||||
CommitSHA: defaultBranchUpdate.New.String(),
|
||||
RepoPath: repo.Path,
|
||||
}),
|
||||
)
|
||||
if err != nil {
|
||||
log.Ctx(ctx).Warn().Err(err).Msg("failed to insert audit log for force push")
|
||||
}
|
||||
}
|
||||
|
|
@ -1,422 +0,0 @@
|
|||
// Copyright 2023 Harness, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package githook
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
apiauth "github.com/harness/gitness/app/api/auth"
|
||||
"github.com/harness/gitness/app/api/controller/limiter"
|
||||
"github.com/harness/gitness/app/api/usererror"
|
||||
"github.com/harness/gitness/app/auth"
|
||||
"github.com/harness/gitness/app/services/protection"
|
||||
"github.com/harness/gitness/git/hook"
|
||||
"github.com/harness/gitness/types"
|
||||
"github.com/harness/gitness/types/enum"
|
||||
|
||||
"github.com/gotidy/ptr"
|
||||
"github.com/rs/zerolog"
|
||||
"golang.org/x/exp/slices"
|
||||
)
|
||||
|
||||
// allowedRepoStatesForPush lists repository states that git push is allowed for internal and external calls.
|
||||
var allowedRepoStatesForPush = []enum.RepoState{enum.RepoStateActive, enum.RepoStateMigrateGitPush}
|
||||
|
||||
// PreReceive executes the pre-receive hook for a git repository.
|
||||
func (c *Controller) PreReceive(
|
||||
ctx context.Context,
|
||||
rgit RestrictedGIT,
|
||||
session *auth.Session,
|
||||
in types.GithookPreReceiveInput,
|
||||
) (hook.Output, error) {
|
||||
output := hook.Output{}
|
||||
defer func() {
|
||||
logOutputFor(ctx, "pre-receive", output)
|
||||
}()
|
||||
|
||||
repo, err := c.getRepoCheckAccess(ctx, session, in.RepoID, enum.PermissionRepoPush)
|
||||
if err != nil {
|
||||
return hook.Output{}, err
|
||||
}
|
||||
|
||||
if !in.Internal && repo.Type == enum.RepoTypeLinked {
|
||||
output.Error = ptr.String("Push not allowed to a linked repository")
|
||||
return output, nil
|
||||
}
|
||||
|
||||
if !in.Internal && !slices.Contains(allowedRepoStatesForPush, repo.State) {
|
||||
output.Error = ptr.String(fmt.Sprintf("Push not allowed when repository is in '%s' state", repo.State))
|
||||
return output, nil
|
||||
}
|
||||
|
||||
if err := c.limiter.RepoSize(ctx, in.RepoID); err != nil {
|
||||
return hook.Output{}, fmt.Errorf(
|
||||
"resource limit exceeded: %w", limiter.ErrMaxRepoSizeReached,
|
||||
)
|
||||
}
|
||||
|
||||
forced := make([]bool, len(in.RefUpdates))
|
||||
for i, refUpdate := range in.RefUpdates {
|
||||
forced[i], err = isForcePush(
|
||||
ctx, rgit, repo.GitUID, in.Environment.AlternateObjectDirs, refUpdate,
|
||||
)
|
||||
if err != nil {
|
||||
return hook.Output{}, fmt.Errorf("failed to check branch ancestor: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
refUpdates := groupRefsByAction(in.RefUpdates, forced)
|
||||
|
||||
if slices.Contains(refUpdates.branches.deleted, repo.DefaultBranch) {
|
||||
// Default branch mustn't be deleted.
|
||||
output.Error = ptr.String(usererror.ErrDefaultBranchCantBeDeleted.Error())
|
||||
return output, nil
|
||||
}
|
||||
|
||||
// For external calls (git pushes) block modification of pullreq references.
|
||||
if !in.Internal && c.blockPullReqRefUpdate(refUpdates, repo.State) {
|
||||
output.Error = ptr.String(usererror.ErrPullReqRefsCantBeModified.Error())
|
||||
return output, nil
|
||||
}
|
||||
|
||||
protectionRules, err := c.protectionManager.ListRepoRules(
|
||||
ctx, repo.ID, protection.TypeBranch, protection.TypeTag, protection.TypePush,
|
||||
)
|
||||
if err != nil {
|
||||
return hook.Output{}, fmt.Errorf(
|
||||
"failed to fetch protection rules for the repository: %w", err,
|
||||
)
|
||||
}
|
||||
|
||||
var principal *types.Principal
|
||||
repoActive := repo.State == enum.RepoStateActive
|
||||
if repoActive {
|
||||
// TODO: use store.PrincipalInfoCache once we abstracted principals.
|
||||
principal, err = c.principalStore.Find(ctx, in.PrincipalID)
|
||||
if err != nil {
|
||||
return hook.Output{}, fmt.Errorf("failed to find inner principal with id %d: %w", in.PrincipalID, err)
|
||||
}
|
||||
}
|
||||
|
||||
var ruleViolations []types.RuleViolations
|
||||
var isRepoOwner bool
|
||||
// For internal calls - through the application interface (API) - no need to verify protection rules.
|
||||
if !in.Internal && repoActive {
|
||||
dummySession := &auth.Session{Principal: *principal, Metadata: nil}
|
||||
isRepoOwner, err = apiauth.IsRepoOwner(ctx, c.authorizer, dummySession, repo)
|
||||
if err != nil {
|
||||
return hook.Output{}, fmt.Errorf("failed to determine if user is repo owner: %w", err)
|
||||
}
|
||||
|
||||
ruleViolations, err = c.checkProtectionRules(
|
||||
ctx, dummySession, repo, refUpdates, protectionRules, isRepoOwner,
|
||||
)
|
||||
if err != nil {
|
||||
return hook.Output{}, fmt.Errorf("failed to check protection rules: %w", err)
|
||||
}
|
||||
if output.Error != nil {
|
||||
return output, nil
|
||||
}
|
||||
}
|
||||
|
||||
err = c.preReceiveExtender.Extend(ctx, rgit, session, repo, in, &output)
|
||||
if err != nil {
|
||||
return hook.Output{}, fmt.Errorf("failed to extend pre-receive hook: %w", err)
|
||||
}
|
||||
if output.Error != nil {
|
||||
return output, nil
|
||||
}
|
||||
|
||||
if repoActive {
|
||||
// check secret scanning apart from push rules as it is enabled in repository settings.
|
||||
err = c.scanSecrets(ctx, rgit, repo, false, nil, in, &output)
|
||||
if err != nil {
|
||||
return hook.Output{}, fmt.Errorf("failed to scan secrets: %w", err)
|
||||
}
|
||||
if output.Error != nil {
|
||||
return output, nil
|
||||
}
|
||||
|
||||
violations, err := c.processPushProtection(
|
||||
ctx, rgit, repo, principal, isRepoOwner, refUpdates, protectionRules, in, &output,
|
||||
)
|
||||
if err != nil {
|
||||
return hook.Output{}, err
|
||||
}
|
||||
ruleViolations = append(ruleViolations, violations...)
|
||||
|
||||
processRuleViolations(&output, ruleViolations)
|
||||
}
|
||||
|
||||
return output, nil
|
||||
}
|
||||
|
||||
// processPushProtection handles push protection verification for active repositories.
|
||||
func (c *Controller) processPushProtection(
|
||||
ctx context.Context,
|
||||
rgit RestrictedGIT,
|
||||
repo *types.RepositoryCore,
|
||||
principal *types.Principal,
|
||||
isRepoOwner bool,
|
||||
refUpdates changedRefs,
|
||||
protectionRules []types.RuleInfoInternal,
|
||||
in types.GithookPreReceiveInput,
|
||||
output *hook.Output,
|
||||
) ([]types.RuleViolations, error) {
|
||||
pushProtection := c.protectionManager.FilterCreatePushProtection(protectionRules)
|
||||
out, _, err := pushProtection.PushVerify(
|
||||
ctx,
|
||||
protection.PushVerifyInput{
|
||||
ResolveUserGroupID: c.userGroupService.ListUserIDsByGroupIDs,
|
||||
Actor: principal,
|
||||
IsRepoOwner: isRepoOwner,
|
||||
RepoID: repo.ID,
|
||||
RepoIdentifier: repo.Identifier,
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to verify git objects: %w", err)
|
||||
}
|
||||
|
||||
if len(out.Protections) == 0 {
|
||||
// No push protections to verify.
|
||||
return []types.RuleViolations{}, nil
|
||||
}
|
||||
|
||||
violationsInput := &protection.PushViolationsInput{
|
||||
ResolveUserGroupID: c.userGroupService.ListUserIDsByGroupIDs,
|
||||
Actor: principal,
|
||||
IsRepoOwner: isRepoOwner,
|
||||
Protections: out.Protections,
|
||||
}
|
||||
|
||||
err = c.scanSecrets(ctx, rgit, repo, out.SecretScanningEnabled, violationsInput, in, output)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to scan secrets: %w", err)
|
||||
}
|
||||
|
||||
if err = c.processObjects(
|
||||
ctx, rgit,
|
||||
repo, principal, refUpdates,
|
||||
out.FileSizeLimit, out.PrincipalCommitterMatch, violationsInput,
|
||||
in, output,
|
||||
); err != nil {
|
||||
return nil, fmt.Errorf("failed to process pre-receive objects: %w", err)
|
||||
}
|
||||
|
||||
var violations []types.RuleViolations
|
||||
if violationsInput.HasViolations() {
|
||||
pushViolations, err := pushProtection.Violations(ctx, violationsInput)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to backfill violations: %w", err)
|
||||
}
|
||||
|
||||
violations = pushViolations.Violations
|
||||
}
|
||||
|
||||
return violations, nil
|
||||
}
|
||||
|
||||
func (c *Controller) blockPullReqRefUpdate(refUpdates changedRefs, state enum.RepoState) bool {
|
||||
if state == enum.RepoStateMigrateGitPush {
|
||||
return false
|
||||
}
|
||||
|
||||
fn := func(ref string) bool {
|
||||
return strings.HasPrefix(ref, gitReferenceNamePullReq)
|
||||
}
|
||||
|
||||
return slices.ContainsFunc(refUpdates.other.created, fn) ||
|
||||
slices.ContainsFunc(refUpdates.other.deleted, fn) ||
|
||||
slices.ContainsFunc(refUpdates.other.updated, fn) ||
|
||||
slices.ContainsFunc(refUpdates.other.forced, fn)
|
||||
}
|
||||
|
||||
func (c *Controller) checkProtectionRules(
|
||||
ctx context.Context,
|
||||
session *auth.Session,
|
||||
repo *types.RepositoryCore,
|
||||
refUpdates changedRefs,
|
||||
protectionRules []types.RuleInfoInternal,
|
||||
isRepoOwner bool,
|
||||
) ([]types.RuleViolations, error) {
|
||||
branchProtection := c.protectionManager.FilterCreateBranchProtection(protectionRules)
|
||||
tagProtection := c.protectionManager.FilterCreateTagProtection(protectionRules)
|
||||
|
||||
var ruleViolations []types.RuleViolations
|
||||
var errCheckAction error
|
||||
|
||||
//nolint:unparam
|
||||
checkAction := func(
|
||||
refProtection protection.RefProtection,
|
||||
refAction protection.RefAction,
|
||||
refType protection.RefType,
|
||||
names []string,
|
||||
) {
|
||||
if errCheckAction != nil || len(names) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
violations, err := refProtection.RefChangeVerify(ctx, protection.RefChangeVerifyInput{
|
||||
ResolveUserGroupID: c.userGroupService.ListUserIDsByGroupIDs,
|
||||
Actor: &session.Principal,
|
||||
AllowBypass: true,
|
||||
IsRepoOwner: isRepoOwner,
|
||||
Repo: repo,
|
||||
RefAction: refAction,
|
||||
RefType: refType,
|
||||
RefNames: names,
|
||||
})
|
||||
if err != nil {
|
||||
errCheckAction = fmt.Errorf("failed to verify protection rules for git push: %w", err)
|
||||
return
|
||||
}
|
||||
|
||||
ruleViolations = append(ruleViolations, violations...)
|
||||
}
|
||||
|
||||
checkAction(
|
||||
branchProtection, protection.RefActionCreate,
|
||||
protection.RefTypeBranch, refUpdates.branches.created,
|
||||
)
|
||||
checkAction(
|
||||
branchProtection, protection.RefActionDelete,
|
||||
protection.RefTypeBranch, refUpdates.branches.deleted,
|
||||
)
|
||||
checkAction(
|
||||
branchProtection, protection.RefActionUpdate,
|
||||
protection.RefTypeBranch, refUpdates.branches.updated,
|
||||
)
|
||||
checkAction(
|
||||
branchProtection, protection.RefActionUpdateForce,
|
||||
protection.RefTypeBranch, refUpdates.branches.forced,
|
||||
)
|
||||
|
||||
checkAction(
|
||||
tagProtection, protection.RefActionCreate,
|
||||
protection.RefTypeTag, refUpdates.tags.created,
|
||||
)
|
||||
checkAction(
|
||||
tagProtection, protection.RefActionDelete,
|
||||
protection.RefTypeTag, refUpdates.tags.deleted,
|
||||
)
|
||||
checkAction(
|
||||
tagProtection, protection.RefActionUpdateForce,
|
||||
protection.RefTypeTag, refUpdates.tags.forced,
|
||||
)
|
||||
|
||||
if errCheckAction != nil {
|
||||
return nil, errCheckAction
|
||||
}
|
||||
|
||||
return ruleViolations, nil
|
||||
}
|
||||
|
||||
func processRuleViolations(
|
||||
output *hook.Output,
|
||||
ruleViolations []types.RuleViolations,
|
||||
) {
|
||||
if len(ruleViolations) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
var criticalViolation bool
|
||||
|
||||
for _, ruleViolation := range ruleViolations {
|
||||
criticalViolation = criticalViolation || ruleViolation.IsCritical()
|
||||
for _, violation := range ruleViolation.Violations {
|
||||
var message string
|
||||
if ruleViolation.Bypassed {
|
||||
message = fmt.Sprintf("Bypassed rule %q: %s", ruleViolation.Rule.Identifier, violation.Message)
|
||||
} else {
|
||||
message = fmt.Sprintf("Rule %q violation: %s", ruleViolation.Rule.Identifier, violation.Message)
|
||||
}
|
||||
output.Messages = append(output.Messages, message)
|
||||
}
|
||||
}
|
||||
|
||||
if criticalViolation {
|
||||
output.Error = ptr.String("Blocked by protection rules.")
|
||||
}
|
||||
}
|
||||
|
||||
type changes struct {
|
||||
created []string
|
||||
deleted []string
|
||||
updated []string
|
||||
forced []string
|
||||
}
|
||||
|
||||
func (c *changes) groupByAction(
|
||||
refUpdate hook.ReferenceUpdate,
|
||||
name string,
|
||||
forced bool,
|
||||
) {
|
||||
switch {
|
||||
case refUpdate.Old.IsNil():
|
||||
c.created = append(c.created, name)
|
||||
case refUpdate.New.IsNil():
|
||||
c.deleted = append(c.deleted, name)
|
||||
case forced:
|
||||
c.forced = append(c.forced, name)
|
||||
default:
|
||||
c.updated = append(c.updated, name)
|
||||
}
|
||||
}
|
||||
|
||||
type changedRefs struct {
|
||||
branches changes
|
||||
tags changes
|
||||
other changes
|
||||
}
|
||||
|
||||
func (c *changedRefs) hasOnlyDeletedBranches() bool {
|
||||
if len(c.branches.created) > 0 || len(c.branches.updated) > 0 || len(c.branches.forced) > 0 {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func isBranch(ref string) bool {
|
||||
return strings.HasPrefix(ref, gitReferenceNamePrefixBranch)
|
||||
}
|
||||
|
||||
func isTag(ref string) bool {
|
||||
return strings.HasPrefix(ref, gitReferenceNamePrefixTag)
|
||||
}
|
||||
|
||||
func groupRefsByAction(refUpdates []hook.ReferenceUpdate, forced []bool) (c changedRefs) {
|
||||
for i, refUpdate := range refUpdates {
|
||||
switch {
|
||||
case isBranch(refUpdate.Ref):
|
||||
branchName := refUpdate.Ref[len(gitReferenceNamePrefixBranch):]
|
||||
c.branches.groupByAction(refUpdate, branchName, forced[i])
|
||||
case isTag(refUpdate.Ref):
|
||||
tagName := refUpdate.Ref[len(gitReferenceNamePrefixTag):]
|
||||
c.tags.groupByAction(refUpdate, tagName, forced[i])
|
||||
default:
|
||||
c.other.groupByAction(refUpdate, refUpdate.Ref, false)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func loggingWithRefUpdate(refUpdate hook.ReferenceUpdate) func(c zerolog.Context) zerolog.Context {
|
||||
return func(c zerolog.Context) zerolog.Context {
|
||||
return c.Str("ref", refUpdate.Ref).Str("old_sha", refUpdate.Old.String()).Str("new_sha", refUpdate.New.String())
|
||||
}
|
||||
}
|
||||
|
|
@ -1,174 +0,0 @@
|
|||
// Copyright 2023 Harness, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package githook
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/harness/gitness/app/services/protection"
|
||||
"github.com/harness/gitness/app/services/settings"
|
||||
"github.com/harness/gitness/git"
|
||||
"github.com/harness/gitness/git/hook"
|
||||
"github.com/harness/gitness/types"
|
||||
|
||||
"github.com/gotidy/ptr"
|
||||
)
|
||||
|
||||
func (c *Controller) processObjects(
|
||||
ctx context.Context,
|
||||
rgit RestrictedGIT,
|
||||
repo *types.RepositoryCore,
|
||||
principal *types.Principal,
|
||||
refUpdates changedRefs,
|
||||
sizeLimit int64,
|
||||
principalCommitterMatch bool,
|
||||
violationsInput *protection.PushViolationsInput,
|
||||
in types.GithookPreReceiveInput,
|
||||
output *hook.Output,
|
||||
) error {
|
||||
if refUpdates.hasOnlyDeletedBranches() {
|
||||
return nil
|
||||
}
|
||||
|
||||
// TODO: Remove this once push rules implementation and migration are complete.
|
||||
settingsSizeLimit, err := settings.RepoGet(
|
||||
ctx,
|
||||
c.settings,
|
||||
repo.ID,
|
||||
settings.KeyFileSizeLimit,
|
||||
settings.DefaultFileSizeLimit,
|
||||
)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to check settings for file size limit: %w", err)
|
||||
}
|
||||
|
||||
if sizeLimit == 0 || (settingsSizeLimit > 0 && sizeLimit > settingsSizeLimit) {
|
||||
sizeLimit = settingsSizeLimit
|
||||
}
|
||||
|
||||
// TODO: Remove this once push rules implementation and migration are complete.
|
||||
if !principalCommitterMatch {
|
||||
principalCommitterMatch, err = settings.RepoGet(
|
||||
ctx,
|
||||
c.settings,
|
||||
repo.ID,
|
||||
settings.KeyPrincipalCommitterMatch,
|
||||
settings.DefaultPrincipalCommitterMatch,
|
||||
)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to check settings for principal committer match: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
gitLFSEnabled, err := settings.RepoGet(
|
||||
ctx,
|
||||
c.settings,
|
||||
repo.ID,
|
||||
settings.KeyGitLFSEnabled,
|
||||
settings.DefaultGitLFSEnabled,
|
||||
)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to check settings for Git LFS enabled: %w", err)
|
||||
}
|
||||
|
||||
if sizeLimit == 0 && !principalCommitterMatch && !gitLFSEnabled {
|
||||
return nil
|
||||
}
|
||||
|
||||
preReceiveObjsIn := git.ProcessPreReceiveObjectsParams{
|
||||
ReadParams: git.ReadParams{
|
||||
RepoUID: repo.GitUID,
|
||||
AlternateObjectDirs: in.Environment.AlternateObjectDirs,
|
||||
},
|
||||
}
|
||||
|
||||
if sizeLimit > 0 {
|
||||
preReceiveObjsIn.FindOversizeFilesParams = &git.FindOversizeFilesParams{
|
||||
SizeLimit: sizeLimit,
|
||||
}
|
||||
}
|
||||
|
||||
if principalCommitterMatch && principal != nil && !in.Internal {
|
||||
preReceiveObjsIn.FindCommitterMismatchParams = &git.FindCommitterMismatchParams{
|
||||
PrincipalEmail: principal.Email,
|
||||
}
|
||||
}
|
||||
|
||||
if gitLFSEnabled {
|
||||
preReceiveObjsIn.FindLFSPointersParams = &git.FindLFSPointersParams{}
|
||||
}
|
||||
|
||||
preReceiveObjsOut, err := rgit.ProcessPreReceiveObjects(
|
||||
ctx,
|
||||
preReceiveObjsIn,
|
||||
)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to process pre-receive objects: %w", err)
|
||||
}
|
||||
|
||||
if preReceiveObjsOut.FindOversizeFilesOutput != nil &&
|
||||
len(preReceiveObjsOut.FindOversizeFilesOutput.FileInfos) > 0 {
|
||||
printOversizeFiles(
|
||||
output,
|
||||
preReceiveObjsOut.FindOversizeFilesOutput.FileInfos,
|
||||
preReceiveObjsOut.FindOversizeFilesOutput.Total,
|
||||
sizeLimit,
|
||||
)
|
||||
}
|
||||
|
||||
if preReceiveObjsOut.FindCommitterMismatchOutput != nil &&
|
||||
len(preReceiveObjsOut.FindCommitterMismatchOutput.CommitInfos) > 0 {
|
||||
printCommitterMismatch(
|
||||
output,
|
||||
preReceiveObjsOut.FindCommitterMismatchOutput.CommitInfos,
|
||||
preReceiveObjsIn.FindCommitterMismatchParams.PrincipalEmail,
|
||||
preReceiveObjsOut.FindCommitterMismatchOutput.Total,
|
||||
)
|
||||
}
|
||||
|
||||
if preReceiveObjsOut.FindLFSPointersOutput != nil &&
|
||||
len(preReceiveObjsOut.FindLFSPointersOutput.LFSInfos) > 0 {
|
||||
objIDs := make([]string, len(preReceiveObjsOut.FindLFSPointersOutput.LFSInfos))
|
||||
for i, info := range preReceiveObjsOut.FindLFSPointersOutput.LFSInfos {
|
||||
objIDs[i] = info.ObjID
|
||||
}
|
||||
|
||||
existingObjs, err := c.lfsStore.FindMany(ctx, in.RepoID, objIDs)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to find lfs objects: %w", err)
|
||||
}
|
||||
|
||||
//nolint:lll
|
||||
if len(existingObjs) != len(objIDs) {
|
||||
output.Error = ptr.String(
|
||||
"Changes blocked by unknown Git LFS objects. Please try `git lfs push --all` or check if LFS is setup properly.")
|
||||
printLFSPointers(
|
||||
output,
|
||||
preReceiveObjsOut.FindLFSPointersOutput.LFSInfos,
|
||||
preReceiveObjsOut.FindLFSPointersOutput.Total,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
violationsInput.FileSizeLimit = sizeLimit
|
||||
violationsInput.FindOversizeFilesOutput = preReceiveObjsOut.FindOversizeFilesOutput
|
||||
violationsInput.PrincipalCommitterMatch = principalCommitterMatch
|
||||
if preReceiveObjsOut.FindCommitterMismatchOutput != nil {
|
||||
violationsInput.CommitterMismatchCount = preReceiveObjsOut.FindCommitterMismatchOutput.Total
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
@ -1,178 +0,0 @@
|
|||
// Copyright 2023 Harness, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package githook
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/harness/gitness/app/services/protection"
|
||||
"github.com/harness/gitness/app/services/settings"
|
||||
"github.com/harness/gitness/git"
|
||||
"github.com/harness/gitness/git/hook"
|
||||
"github.com/harness/gitness/logging"
|
||||
"github.com/harness/gitness/types"
|
||||
|
||||
"github.com/gotidy/ptr"
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
type secretFinding struct {
|
||||
git.ScanSecretsFinding
|
||||
Ref string
|
||||
}
|
||||
|
||||
func (c *Controller) scanSecrets(
|
||||
ctx context.Context,
|
||||
rgit RestrictedGIT,
|
||||
repo *types.RepositoryCore,
|
||||
scanningEnabled bool,
|
||||
violationsInput *protection.PushViolationsInput,
|
||||
in types.GithookPreReceiveInput,
|
||||
output *hook.Output,
|
||||
) error {
|
||||
if !scanningEnabled {
|
||||
var err error
|
||||
scanningEnabled, err = settings.RepoGet(
|
||||
ctx,
|
||||
c.settings,
|
||||
repo.ID,
|
||||
settings.KeySecretScanningEnabled,
|
||||
settings.DefaultSecretScanningEnabled,
|
||||
)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to check settings whether secret scanning is enabled: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
if !scanningEnabled {
|
||||
return nil
|
||||
}
|
||||
|
||||
// scan for secrets
|
||||
startTime := time.Now()
|
||||
findings, err := scanSecretsInternal(
|
||||
ctx,
|
||||
rgit,
|
||||
repo,
|
||||
in,
|
||||
)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to scan for git leaks: %w", err)
|
||||
}
|
||||
|
||||
// always print result (handles both no results and results found)
|
||||
printScanSecretsFindings(output, findings, len(in.RefUpdates) > 1, time.Since(startTime))
|
||||
|
||||
// this will be removed when secret scanning check will be moved to push protection
|
||||
if len(findings) > 0 && violationsInput == nil {
|
||||
errMsg := fmt.Sprintf("Found %d secret(s) in your code. Push rejected.", len(findings))
|
||||
output.Error = ptr.String(errMsg)
|
||||
}
|
||||
|
||||
if violationsInput != nil {
|
||||
violationsInput.SecretScanningEnabled = scanningEnabled
|
||||
violationsInput.FoundSecretCount = len(findings)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func scanSecretsInternal(ctx context.Context,
|
||||
rgit RestrictedGIT,
|
||||
repo *types.RepositoryCore,
|
||||
in types.GithookPreReceiveInput,
|
||||
) ([]secretFinding, error) {
|
||||
var baseRevFallBack *string
|
||||
findings := []secretFinding{}
|
||||
|
||||
for _, refUpdate := range in.RefUpdates {
|
||||
ctx := logging.NewContext(ctx, loggingWithRefUpdate(refUpdate))
|
||||
log := log.Ctx(ctx)
|
||||
|
||||
if refUpdate.New.IsNil() {
|
||||
log.Debug().Msg("skip deleted reference")
|
||||
continue
|
||||
}
|
||||
|
||||
// in case the branch was just created - fallback to compare against latest default branch.
|
||||
baseRev := refUpdate.Old.String() + "^{commit}" //nolint:goconst
|
||||
rev := refUpdate.New.String() + "^{commit}" //nolint:goconst
|
||||
//nolint:nestif
|
||||
if refUpdate.Old.IsNil() {
|
||||
if baseRevFallBack == nil {
|
||||
fallbackSHA, fallbackAvailable, err := GetBaseSHAForScanningChanges(
|
||||
ctx,
|
||||
rgit,
|
||||
repo,
|
||||
in.Environment,
|
||||
in.RefUpdates,
|
||||
refUpdate,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get fallback sha: %w", err)
|
||||
}
|
||||
|
||||
if fallbackAvailable {
|
||||
log.Debug().Msgf("found fallback sha %q", fallbackSHA)
|
||||
baseRevFallBack = ptr.String(fallbackSHA.String())
|
||||
} else {
|
||||
log.Debug().Msg("no fallback sha available, do full scan instead")
|
||||
baseRevFallBack = ptr.String("")
|
||||
}
|
||||
}
|
||||
|
||||
log.Debug().Msgf("new reference, use rev %q as base for secret scanning", *baseRevFallBack)
|
||||
|
||||
baseRev = *baseRevFallBack
|
||||
}
|
||||
|
||||
log.Debug().Msg("scan for secrets")
|
||||
|
||||
scanSecretsOut, err := rgit.ScanSecrets(ctx, &git.ScanSecretsParams{
|
||||
ReadParams: git.ReadParams{
|
||||
RepoUID: repo.GitUID,
|
||||
AlternateObjectDirs: in.Environment.AlternateObjectDirs,
|
||||
},
|
||||
BaseRev: baseRev,
|
||||
Rev: rev,
|
||||
GitleaksIgnorePath: git.DefaultGitleaksIgnorePath,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to detect secret leaks: %w", err)
|
||||
}
|
||||
|
||||
if len(scanSecretsOut.Findings) == 0 {
|
||||
log.Debug().Msg("no new secrets found")
|
||||
continue
|
||||
}
|
||||
|
||||
log.Debug().Msgf("found %d new secrets", len(scanSecretsOut.Findings))
|
||||
|
||||
for _, finding := range scanSecretsOut.Findings {
|
||||
findings = append(findings, secretFinding{
|
||||
ScanSecretsFinding: finding,
|
||||
Ref: refUpdate.Ref,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
if len(findings) > 0 {
|
||||
log.Ctx(ctx).Debug().Msgf("found total of %d new secrets", len(findings))
|
||||
}
|
||||
|
||||
return findings, nil
|
||||
}
|
||||
|
|
@ -1,210 +0,0 @@
|
|||
// Copyright 2023 Harness, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package githook
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/harness/gitness/git"
|
||||
"github.com/harness/gitness/git/hook"
|
||||
|
||||
"github.com/fatih/color"
|
||||
)
|
||||
|
||||
var (
|
||||
colorScanHeader = color.New(color.FgHiWhite, color.Underline)
|
||||
colorScanSummary = color.New(color.FgHiRed, color.Bold)
|
||||
colorScanSummaryNoFindings = color.New(color.FgHiGreen, color.Bold)
|
||||
)
|
||||
|
||||
func printScanSecretsFindings(
|
||||
output *hook.Output,
|
||||
findings []secretFinding,
|
||||
multipleRefs bool,
|
||||
duration time.Duration,
|
||||
) {
|
||||
findingsCnt := len(findings)
|
||||
|
||||
// no results? output success and continue
|
||||
if findingsCnt == 0 {
|
||||
output.Messages = append(
|
||||
output.Messages,
|
||||
colorScanSummaryNoFindings.Sprintf("No secrets found")+
|
||||
fmt.Sprintf(" in %s", duration.Round(time.Millisecond)),
|
||||
"", "", // add two empty lines for making it visually more consumable
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
output.Messages = append(
|
||||
output.Messages,
|
||||
colorScanHeader.Sprintf(
|
||||
"Push contains %s:",
|
||||
singularOrPlural("secret", findingsCnt > 1),
|
||||
),
|
||||
"", // add empty line for making it visually more consumable
|
||||
)
|
||||
|
||||
for _, finding := range findings {
|
||||
headerTxt := fmt.Sprintf("%s in %s:%d", finding.RuleID, finding.File, finding.StartLine)
|
||||
if finding.StartLine != finding.EndLine {
|
||||
headerTxt += fmt.Sprintf("-%d", finding.EndLine)
|
||||
}
|
||||
if multipleRefs {
|
||||
headerTxt += fmt.Sprintf(" [%s]", finding.Ref)
|
||||
}
|
||||
|
||||
output.Messages = append(
|
||||
output.Messages,
|
||||
fmt.Sprintf(" %s", headerTxt),
|
||||
fmt.Sprintf(" Secret: %s", finding.Secret),
|
||||
fmt.Sprintf(" Commit: %s", finding.Commit),
|
||||
fmt.Sprintf(" Details: %s", finding.Description),
|
||||
fmt.Sprintf(" Fingerprint: %s", finding.Fingerprint),
|
||||
"", // add empty line for making it visually more consumable
|
||||
)
|
||||
}
|
||||
|
||||
output.Messages = append(
|
||||
output.Messages,
|
||||
colorScanSummary.Sprintf(
|
||||
"%d %s found",
|
||||
findingsCnt,
|
||||
singularOrPlural("secret", findingsCnt > 1),
|
||||
)+fmt.Sprintf(" in %s", FMTDuration(time.Millisecond)),
|
||||
"", "", // add two empty lines for making it visually more consumable
|
||||
)
|
||||
}
|
||||
|
||||
func FMTDuration(d time.Duration) string {
|
||||
const secondsRounding = time.Second / time.Duration(10)
|
||||
switch {
|
||||
case d <= time.Millisecond:
|
||||
// keep anything under a millisecond untouched
|
||||
case d < time.Second:
|
||||
d = d.Round(time.Millisecond) // round under a second to millisecondss
|
||||
case d < time.Minute:
|
||||
d = d.Round(secondsRounding) // round under a minute to .1 precision
|
||||
default:
|
||||
d = d.Round(time.Second) // keep rest at second precision
|
||||
}
|
||||
return d.String()
|
||||
}
|
||||
|
||||
func printOversizeFiles(
|
||||
output *hook.Output,
|
||||
oversizeFiles []git.FileInfo,
|
||||
total int64,
|
||||
sizeLimit int64,
|
||||
) {
|
||||
output.Messages = append(
|
||||
output.Messages,
|
||||
colorScanHeader.Sprintf(
|
||||
"Push contains files exceeding the size limit:",
|
||||
),
|
||||
"", // add empty line for making it visually more consumable
|
||||
)
|
||||
|
||||
for _, file := range oversizeFiles {
|
||||
output.Messages = append(
|
||||
output.Messages,
|
||||
fmt.Sprintf(" %s", file.SHA),
|
||||
fmt.Sprintf(" Size: %dB", file.Size),
|
||||
"", // add empty line for making it visually more consumable
|
||||
)
|
||||
}
|
||||
|
||||
output.Messages = append(
|
||||
output.Messages,
|
||||
colorScanSummary.Sprintf(
|
||||
"%d %s found exceeding the size limit of %dB",
|
||||
total, singularOrPlural("file", total > 1), sizeLimit,
|
||||
),
|
||||
"", "", // add two empty lines for making it visually more consumable
|
||||
)
|
||||
}
|
||||
|
||||
func printCommitterMismatch(
|
||||
output *hook.Output,
|
||||
commitInfos []git.CommitInfo,
|
||||
principalEmail string,
|
||||
total int64,
|
||||
) {
|
||||
output.Messages = append(
|
||||
output.Messages,
|
||||
colorScanHeader.Sprintf(
|
||||
"Push contains commits where committer is not the authenticated user (%s):",
|
||||
principalEmail,
|
||||
),
|
||||
"", // add empty line for making it visually more consumable
|
||||
)
|
||||
|
||||
for _, info := range commitInfos {
|
||||
output.Messages = append(
|
||||
output.Messages,
|
||||
fmt.Sprintf(" %s Committer: %s", info.SHA, info.Committer),
|
||||
"", // add empty line for making it visually more consumable
|
||||
)
|
||||
}
|
||||
|
||||
output.Messages = append(
|
||||
output.Messages,
|
||||
colorScanSummary.Sprintf(
|
||||
"%d %s found not matching the authenticated user (%s)",
|
||||
total, singularOrPlural("commit", total > 1), principalEmail,
|
||||
),
|
||||
"", "", // add two empty lines for making it visually more consumable
|
||||
)
|
||||
}
|
||||
|
||||
func printLFSPointers(
|
||||
output *hook.Output,
|
||||
lfsInfos []git.LFSInfo,
|
||||
total int64,
|
||||
) {
|
||||
output.Messages = append(
|
||||
output.Messages,
|
||||
colorScanHeader.Sprintf(
|
||||
"Push references unknown LFS objects:",
|
||||
),
|
||||
"", // add empty line for making it visually more consumable
|
||||
)
|
||||
|
||||
for _, info := range lfsInfos {
|
||||
output.Messages = append(
|
||||
output.Messages,
|
||||
fmt.Sprintf(" Object ID: %s", info.ObjID),
|
||||
fmt.Sprintf(" File SHA : %s", info.SHA),
|
||||
"", // add empty line for making it visually more consumable
|
||||
)
|
||||
}
|
||||
|
||||
output.Messages = append(
|
||||
output.Messages,
|
||||
colorScanSummary.Sprintf(
|
||||
"%d %s missing",
|
||||
total, singularOrPlural("LFS object", total > 1),
|
||||
),
|
||||
"", "", // add two empty lines for making it visually more consumable
|
||||
)
|
||||
}
|
||||
|
||||
func singularOrPlural(noun string, plural bool) string {
|
||||
if plural {
|
||||
return noun + "s"
|
||||
}
|
||||
return noun
|
||||
}
|
||||
|
|
@ -1,48 +0,0 @@
|
|||
// Copyright 2023 Harness, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package githook
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/harness/gitness/app/auth"
|
||||
"github.com/harness/gitness/git/hook"
|
||||
"github.com/harness/gitness/types"
|
||||
"github.com/harness/gitness/types/enum"
|
||||
)
|
||||
|
||||
// Update executes the update hook for a git repository.
|
||||
func (c *Controller) Update(
|
||||
ctx context.Context,
|
||||
rgit RestrictedGIT,
|
||||
session *auth.Session,
|
||||
in types.GithookUpdateInput,
|
||||
) (hook.Output, error) {
|
||||
repo, err := c.getRepoCheckAccess(ctx, session, in.RepoID, enum.PermissionRepoPush)
|
||||
if err != nil {
|
||||
return hook.Output{}, err
|
||||
}
|
||||
|
||||
output := hook.Output{}
|
||||
|
||||
err = c.updateExtender.Extend(ctx, rgit, session, repo, in, &output)
|
||||
if err != nil {
|
||||
return hook.Output{}, fmt.Errorf("failed to extend update hook: %w", err)
|
||||
}
|
||||
|
||||
// We currently don't have any update action (nothing planned as of now)
|
||||
return hook.Output{}, nil
|
||||
}
|
||||
|
|
@ -1,117 +0,0 @@
|
|||
// Copyright 2023 Harness, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package githook
|
||||
|
||||
import (
|
||||
"github.com/harness/gitness/app/api/controller/limiter"
|
||||
"github.com/harness/gitness/app/auth/authz"
|
||||
eventsgit "github.com/harness/gitness/app/events/git"
|
||||
eventsrepo "github.com/harness/gitness/app/events/repo"
|
||||
"github.com/harness/gitness/app/services/protection"
|
||||
"github.com/harness/gitness/app/services/refcache"
|
||||
"github.com/harness/gitness/app/services/settings"
|
||||
"github.com/harness/gitness/app/services/usergroup"
|
||||
"github.com/harness/gitness/app/sse"
|
||||
"github.com/harness/gitness/app/store"
|
||||
"github.com/harness/gitness/app/url"
|
||||
"github.com/harness/gitness/audit"
|
||||
"github.com/harness/gitness/git"
|
||||
"github.com/harness/gitness/git/hook"
|
||||
|
||||
"github.com/google/wire"
|
||||
)
|
||||
|
||||
var WireSet = wire.NewSet(
|
||||
ProvideController,
|
||||
ProvideFactory,
|
||||
)
|
||||
|
||||
func ProvideFactory() hook.ClientFactory {
|
||||
return &ControllerClientFactory{
|
||||
// fields are set in ProvideController to avoid import
|
||||
githookCtrl: nil,
|
||||
git: nil,
|
||||
}
|
||||
}
|
||||
|
||||
func ProvideController(
|
||||
authorizer authz.Authorizer,
|
||||
principalStore store.PrincipalStore,
|
||||
repoStore store.RepoStore,
|
||||
repoFinder refcache.RepoFinder,
|
||||
gitReporter *eventsgit.Reporter,
|
||||
repoReporter *eventsrepo.Reporter,
|
||||
git git.Interface,
|
||||
pullreqStore store.PullReqStore,
|
||||
urlProvider url.Provider,
|
||||
protectionManager *protection.Manager,
|
||||
githookFactory hook.ClientFactory,
|
||||
limiter limiter.ResourceLimiter,
|
||||
settings *settings.Service,
|
||||
preReceiveExtender PreReceiveExtender,
|
||||
updateExtender UpdateExtender,
|
||||
postReceiveExtender PostReceiveExtender,
|
||||
sseStreamer sse.Streamer,
|
||||
lfsStore store.LFSObjectStore,
|
||||
auditService audit.Service,
|
||||
userGroupService usergroup.Service,
|
||||
) *Controller {
|
||||
ctrl := NewController(
|
||||
authorizer,
|
||||
principalStore,
|
||||
repoStore,
|
||||
repoFinder,
|
||||
gitReporter,
|
||||
repoReporter,
|
||||
pullreqStore,
|
||||
urlProvider,
|
||||
protectionManager,
|
||||
limiter,
|
||||
settings,
|
||||
preReceiveExtender,
|
||||
updateExtender,
|
||||
postReceiveExtender,
|
||||
sseStreamer,
|
||||
lfsStore,
|
||||
auditService,
|
||||
userGroupService,
|
||||
)
|
||||
|
||||
// TODO: improve wiring if possible
|
||||
if fct, ok := githookFactory.(*ControllerClientFactory); ok {
|
||||
fct.githookCtrl = ctrl
|
||||
fct.git = git
|
||||
}
|
||||
|
||||
return ctrl
|
||||
}
|
||||
|
||||
var ExtenderWireSet = wire.NewSet(
|
||||
ProvidePreReceiveExtender,
|
||||
ProvideUpdateExtender,
|
||||
ProvidePostReceiveExtender,
|
||||
)
|
||||
|
||||
func ProvidePreReceiveExtender() (PreReceiveExtender, error) {
|
||||
return NewPreReceiveExtender(), nil
|
||||
}
|
||||
|
||||
func ProvideUpdateExtender() (UpdateExtender, error) {
|
||||
return NewUpdateExtender(), nil
|
||||
}
|
||||
|
||||
func ProvidePostReceiveExtender() (PostReceiveExtender, error) {
|
||||
return NewPostReceiveExtender(), nil
|
||||
}
|
||||
|
|
@ -1,118 +0,0 @@
|
|||
// Copyright 2023 Harness, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package gitspace
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
apiauth "github.com/harness/gitness/app/api/auth"
|
||||
"github.com/harness/gitness/app/auth"
|
||||
"github.com/harness/gitness/types"
|
||||
"github.com/harness/gitness/types/check"
|
||||
"github.com/harness/gitness/types/enum"
|
||||
)
|
||||
|
||||
type ActionInput struct {
|
||||
Action enum.GitspaceActionType `json:"action"`
|
||||
Identifier string `json:"-"`
|
||||
SpaceRef string `json:"-"` // Ref of the parent space
|
||||
}
|
||||
|
||||
func (c *Controller) Action(
|
||||
ctx context.Context,
|
||||
session *auth.Session,
|
||||
in *ActionInput,
|
||||
) (*types.GitspaceConfig, error) {
|
||||
if err := c.sanitizeActionInput(in); err != nil {
|
||||
return nil, fmt.Errorf("failed to sanitize input: %w", err)
|
||||
}
|
||||
space, err := c.spaceFinder.FindByRef(ctx, in.SpaceRef)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to find space: %w", err)
|
||||
}
|
||||
err = apiauth.CheckGitspace(ctx, c.authorizer, session, space.Path, in.Identifier, enum.PermissionGitspaceUse)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to authorize: %w", err)
|
||||
}
|
||||
|
||||
gitspaceConfig, err := c.gitspaceSvc.FindWithLatestInstance(ctx, space.ID, in.Identifier)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to find gitspace config: %w", err)
|
||||
}
|
||||
// check if it's an internal repo
|
||||
if gitspaceConfig.CodeRepo.Type == enum.CodeRepoTypeGitness {
|
||||
if gitspaceConfig.CodeRepo.Ref == nil {
|
||||
return nil, fmt.Errorf("couldn't fetch repo for the user, no ref found: %w", err)
|
||||
}
|
||||
repo, err := c.repoFinder.FindByRef(ctx, *gitspaceConfig.CodeRepo.Ref)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("couldn't fetch repo for the user: %w", err)
|
||||
}
|
||||
if err = apiauth.CheckRepo(
|
||||
ctx,
|
||||
c.authorizer,
|
||||
session,
|
||||
repo,
|
||||
enum.PermissionRepoView); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
gitspaceConfig.BranchURL = c.gitspaceSvc.GetBranchURL(ctx, gitspaceConfig)
|
||||
|
||||
// All the actions should be idempotent.
|
||||
switch in.Action {
|
||||
case enum.GitspaceActionTypeStart:
|
||||
err = c.gitspaceLimiter.Usage(ctx, space.ID, gitspaceConfig.InfraProviderResource.InfraProviderType)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
c.gitspaceSvc.EmitGitspaceConfigEvent(ctx, *gitspaceConfig, enum.GitspaceEventTypeGitspaceActionStart)
|
||||
if err = c.gitspaceSvc.StartGitspaceAction(ctx, *gitspaceConfig); err == nil {
|
||||
gitspaceConfig.State = enum.GitspaceStateStarting
|
||||
}
|
||||
return gitspaceConfig, err
|
||||
case enum.GitspaceActionTypeStop:
|
||||
c.gitspaceSvc.EmitGitspaceConfigEvent(ctx, *gitspaceConfig, enum.GitspaceEventTypeGitspaceActionStop)
|
||||
if err = c.gitspaceSvc.StopGitspaceAction(ctx, *gitspaceConfig, time.Now()); err == nil {
|
||||
gitspaceConfig.State = enum.GitspaceStateStopping
|
||||
}
|
||||
return gitspaceConfig, err
|
||||
case enum.GitspaceActionTypeReset:
|
||||
c.gitspaceSvc.EmitGitspaceConfigEvent(ctx, *gitspaceConfig, enum.GitspaceEventTypeGitspaceActionReset)
|
||||
if err = c.gitspaceSvc.ResetGitspaceAction(ctx, *gitspaceConfig); err == nil {
|
||||
gitspaceConfig.State = enum.GitSpaceStateCleaning
|
||||
}
|
||||
return gitspaceConfig, err
|
||||
default:
|
||||
return nil, fmt.Errorf("unknown action %s on gitspace : %s", string(in.Action), gitspaceConfig.Identifier)
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Controller) sanitizeActionInput(in *ActionInput) error {
|
||||
if err := check.Identifier(in.Identifier); err != nil {
|
||||
return err
|
||||
}
|
||||
parentRefAsID, err := strconv.ParseInt(in.SpaceRef, 10, 64)
|
||||
if (err == nil && parentRefAsID <= 0) || (len(strings.TrimSpace(in.SpaceRef)) == 0) {
|
||||
return ErrGitspaceRequiresParent
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
@ -1,225 +0,0 @@
|
|||
// Copyright 2023 Harness, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package common
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
"github.com/harness/gitness/app/api/usererror"
|
||||
"github.com/harness/gitness/types"
|
||||
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
// FilterResourcesByCompatibility filters resources based on compatibility with a reference resource.
|
||||
// It removes any resources that are not compatible according to the IsResourceSpecChangeAllowed criteria.
|
||||
func FilterResourcesByCompatibility(
|
||||
ctx context.Context,
|
||||
filteredResources []*types.InfraProviderResource,
|
||||
referenceResource *types.InfraProviderResource,
|
||||
) ([]*types.InfraProviderResource, error) {
|
||||
if referenceResource == nil {
|
||||
return nil, fmt.Errorf("referenceResource cannot be nil")
|
||||
}
|
||||
|
||||
compatibleResources := make([]*types.InfraProviderResource, 0)
|
||||
|
||||
// Now filter based on compatibility
|
||||
for _, resource := range filteredResources {
|
||||
// Skip the current resource itself
|
||||
if resource.UID == referenceResource.UID {
|
||||
continue
|
||||
}
|
||||
|
||||
_, err := IsResourceSpecChangeAllowed(referenceResource, resource)
|
||||
if err != nil {
|
||||
log.Ctx(ctx).Debug().
|
||||
Err(err).
|
||||
Str("resource_id", resource.UID).
|
||||
Str("reference_id", referenceResource.UID).
|
||||
Msg("resource compatibility check failed")
|
||||
} else {
|
||||
compatibleResources = append(compatibleResources, resource)
|
||||
}
|
||||
}
|
||||
|
||||
return compatibleResources, nil
|
||||
}
|
||||
|
||||
// IsResourceSpecChangeAllowed checks if the new resource specs are valid and determines if a hard reset is needed.
|
||||
// Returns (markForHardReset, error) where error contains details about why the validation failed.
|
||||
func IsResourceSpecChangeAllowed(
|
||||
existingResource *types.InfraProviderResource,
|
||||
newResource *types.InfraProviderResource,
|
||||
) (bool, error) {
|
||||
// If either resource is nil, we can't compare properly
|
||||
if existingResource == nil || newResource == nil {
|
||||
return false, fmt.Errorf("cannot validate resource change: missing resource information")
|
||||
}
|
||||
|
||||
// Validate region is the same
|
||||
if existingResource.Region != newResource.Region {
|
||||
return false, usererror.BadRequestf(
|
||||
"region mismatch: current region '%s' does not match target region '%s'",
|
||||
existingResource.Region, newResource.Region)
|
||||
}
|
||||
|
||||
// Check zone from metadata if available
|
||||
existingZone, existingHasZone := existingResource.Metadata["zone"]
|
||||
newZone, newHasZone := newResource.Metadata["zone"]
|
||||
|
||||
// If both resources have zone info, they must match
|
||||
if existingHasZone && newHasZone && existingZone != newZone {
|
||||
return false, usererror.BadRequestf(
|
||||
"zone mismatch: current zone '%s' does not match target zone '%s'",
|
||||
existingZone, newZone,
|
||||
)
|
||||
}
|
||||
|
||||
markForInfraReset := false
|
||||
|
||||
// Check boot disk changes
|
||||
needsHardReset, err := validateBootDiskChanges(existingResource.Metadata, newResource.Metadata)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if needsHardReset {
|
||||
markForInfraReset = true
|
||||
}
|
||||
|
||||
// Check persistent disk changes
|
||||
needsHardReset, err = validatePersistentDiskChanges(existingResource.Metadata, newResource.Metadata)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if needsHardReset {
|
||||
markForInfraReset = true
|
||||
}
|
||||
|
||||
// Check machine type changes
|
||||
machineTypeResetNeeded := validateMachineTypeChanges(existingResource.Metadata, newResource.Metadata)
|
||||
markForInfraReset = markForInfraReset || machineTypeResetNeeded
|
||||
|
||||
// All checks passed
|
||||
return markForInfraReset, nil
|
||||
}
|
||||
|
||||
// validatePersistentDiskChanges checks if persistent disk changes are valid and if they require a hard reset.
|
||||
// Returns (needsHardReset, error).
|
||||
func validatePersistentDiskChanges(existingMeta, newMeta map[string]string) (bool, error) {
|
||||
existingDisk, existingOK := existingMeta["persistent_disk_size"]
|
||||
newDisk, newOK := newMeta["persistent_disk_size"]
|
||||
if !existingOK || !newOK {
|
||||
return false, fmt.Errorf(
|
||||
"invalid persistent disk size format: cannot parse persistent disk sizes for comparison")
|
||||
}
|
||||
|
||||
markForHardReset, err := checkPersistentDiskSizeChange(existingDisk, newDisk)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
existingDiskType, existingOK := existingMeta["persistent_disk_type"]
|
||||
newDiskType, newOK := newMeta["persistent_disk_type"]
|
||||
if !existingOK || !newOK {
|
||||
return false, fmt.Errorf(
|
||||
"invalid persistent disk type format: cannot parse persistent disk types for comparison")
|
||||
}
|
||||
if existingDiskType != newDiskType {
|
||||
return false, usererror.BadRequestf(
|
||||
"persistent disk type change not allowed: from '%s' to '%s'",
|
||||
existingDiskType, newDiskType)
|
||||
}
|
||||
|
||||
return markForHardReset, nil
|
||||
}
|
||||
|
||||
// validateMachineTypeChanges checks if machine type changes require a hard reset.
|
||||
// Returns needsHardReset.
|
||||
func validateMachineTypeChanges(existingMeta, newMeta map[string]string) bool {
|
||||
existingMachine, existingOK := existingMeta["machine_type"]
|
||||
newMachine, newOK := newMeta["machine_type"]
|
||||
if existingOK && newOK && existingMachine != newMachine {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// validateBootDiskChanges checks if boot disk changes are valid and if they require a hard reset.
|
||||
// Returns (needsHardReset, error).
|
||||
func validateBootDiskChanges(existingMeta, newMeta map[string]string) (bool, error) {
|
||||
markForHardReset := false
|
||||
|
||||
// Check boot disk size changes
|
||||
existingBoot, existingOK := existingMeta["boot_disk_size"]
|
||||
newBoot, newOK := newMeta["boot_disk_size"]
|
||||
if !existingOK || !newOK {
|
||||
return false, fmt.Errorf(
|
||||
"invalid boot disk size format: cannot parse boot disk sizes for comparison")
|
||||
}
|
||||
|
||||
existingVal, eErr := strconv.Atoi(existingBoot)
|
||||
newVal, nErr := strconv.Atoi(newBoot)
|
||||
if eErr != nil || nErr != nil {
|
||||
return false, fmt.Errorf(
|
||||
"invalid boot disk size format: cannot parse boot disk sizes for comparison")
|
||||
}
|
||||
if newVal != existingVal {
|
||||
markForHardReset = true
|
||||
}
|
||||
|
||||
// Check boot disk type changes
|
||||
existingBootType, existingOK := existingMeta["boot_disk_type"]
|
||||
newBootType, newOK := newMeta["boot_disk_type"]
|
||||
if !existingOK || !newOK {
|
||||
return false, fmt.Errorf(
|
||||
"invalid boot disk type format: cannot parse boot disk types for comparison")
|
||||
}
|
||||
if existingBootType != newBootType {
|
||||
markForHardReset = true
|
||||
}
|
||||
|
||||
return markForHardReset, nil
|
||||
}
|
||||
|
||||
// checkPersistentDiskSizeChange compares existing and new persistent disk sizes.
|
||||
// and determines if the change is allowed and if hard reset is needed.
|
||||
// Returns (needsHardReset, error).
|
||||
//
|
||||
//nolint:unparam // the bool return value is kept for future extension
|
||||
func checkPersistentDiskSizeChange(existingDisk, newDisk string) (bool, error) {
|
||||
existingVal, eErr := strconv.Atoi(existingDisk)
|
||||
if eErr != nil {
|
||||
return false, fmt.Errorf("invalid disk size format: cannot parse existing disk size: %w", eErr)
|
||||
}
|
||||
|
||||
newVal, nErr := strconv.Atoi(newDisk)
|
||||
if nErr != nil {
|
||||
return false, fmt.Errorf("invalid disk size format: cannot parse new disk size: %w", nErr)
|
||||
}
|
||||
|
||||
// Disallow any changes to persistent disk size
|
||||
if newVal != existingVal {
|
||||
return false, fmt.Errorf(
|
||||
"changing persistent disk size is not allowed: from %d to %d",
|
||||
existingVal, newVal)
|
||||
}
|
||||
|
||||
// Equal sizes, no hard reset needed
|
||||
return false, nil
|
||||
}
|
||||
|
|
@ -1,73 +0,0 @@
|
|||
// Copyright 2023 Harness, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package gitspace
|
||||
|
||||
import (
|
||||
"github.com/harness/gitness/app/api/controller/limiter"
|
||||
"github.com/harness/gitness/app/auth/authz"
|
||||
"github.com/harness/gitness/app/gitspace/logutil"
|
||||
"github.com/harness/gitness/app/gitspace/scm"
|
||||
"github.com/harness/gitness/app/services/gitspace"
|
||||
"github.com/harness/gitness/app/services/gitspacesettings"
|
||||
"github.com/harness/gitness/app/services/infraprovider"
|
||||
"github.com/harness/gitness/app/services/refcache"
|
||||
"github.com/harness/gitness/app/store"
|
||||
"github.com/harness/gitness/store/database/dbtx"
|
||||
)
|
||||
|
||||
type Controller struct {
|
||||
authorizer authz.Authorizer
|
||||
infraProviderSvc *infraprovider.Service
|
||||
spaceStore store.SpaceStore
|
||||
spaceFinder refcache.SpaceFinder
|
||||
gitspaceEventStore store.GitspaceEventStore
|
||||
tx dbtx.Transactor
|
||||
statefulLogger *logutil.StatefulLogger
|
||||
scm *scm.SCM
|
||||
gitspaceSvc *gitspace.Service
|
||||
gitspaceLimiter limiter.Gitspace
|
||||
repoFinder refcache.RepoFinder
|
||||
settingsService gitspacesettings.Service
|
||||
}
|
||||
|
||||
func NewController(
|
||||
tx dbtx.Transactor,
|
||||
authorizer authz.Authorizer,
|
||||
infraProviderSvc *infraprovider.Service,
|
||||
spaceStore store.SpaceStore,
|
||||
spaceFinder refcache.SpaceFinder,
|
||||
gitspaceEventStore store.GitspaceEventStore,
|
||||
statefulLogger *logutil.StatefulLogger,
|
||||
scm *scm.SCM,
|
||||
gitspaceSvc *gitspace.Service,
|
||||
gitspaceLimiter limiter.Gitspace,
|
||||
repoFinder refcache.RepoFinder,
|
||||
settingsService gitspacesettings.Service,
|
||||
) *Controller {
|
||||
return &Controller{
|
||||
tx: tx,
|
||||
authorizer: authorizer,
|
||||
infraProviderSvc: infraProviderSvc,
|
||||
spaceStore: spaceStore,
|
||||
spaceFinder: spaceFinder,
|
||||
gitspaceEventStore: gitspaceEventStore,
|
||||
statefulLogger: statefulLogger,
|
||||
scm: scm,
|
||||
gitspaceSvc: gitspaceSvc,
|
||||
gitspaceLimiter: gitspaceLimiter,
|
||||
repoFinder: repoFinder,
|
||||
settingsService: settingsService,
|
||||
}
|
||||
}
|
||||
|
|
@ -1,324 +0,0 @@
|
|||
// Copyright 2023 Harness, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package gitspace
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
apiauth "github.com/harness/gitness/app/api/auth"
|
||||
"github.com/harness/gitness/app/api/usererror"
|
||||
"github.com/harness/gitness/app/auth"
|
||||
"github.com/harness/gitness/app/paths"
|
||||
"github.com/harness/gitness/app/services/gitspace"
|
||||
"github.com/harness/gitness/errors"
|
||||
"github.com/harness/gitness/store"
|
||||
"github.com/harness/gitness/types"
|
||||
"github.com/harness/gitness/types/check"
|
||||
"github.com/harness/gitness/types/enum"
|
||||
|
||||
gonanoid "github.com/matoous/go-nanoid"
|
||||
)
|
||||
|
||||
const (
|
||||
defaultResourceIdentifier = "default"
|
||||
maxGitspaceConfigIdentifierPrefixLength = 50
|
||||
suffixLen = 6
|
||||
)
|
||||
|
||||
var (
|
||||
// ErrGitspaceRequiresParent if the user tries to create a secret without a parent space.
|
||||
ErrGitspaceRequiresParent = usererror.BadRequest(
|
||||
"Parent space required - standalone gitspace are not supported.")
|
||||
)
|
||||
|
||||
// CreateInput is the input used for create operations.
|
||||
type CreateInput struct {
|
||||
Identifier string `json:"identifier"`
|
||||
Name string `json:"name"`
|
||||
SpaceRef string `json:"space_ref"` // Ref of the parent space
|
||||
IDE enum.IDEType `json:"ide"`
|
||||
InfraProviderConfigIdentifier string `json:"infra_provider_config_identifier"`
|
||||
ResourceIdentifier string `json:"resource_identifier"`
|
||||
ResourceSpaceRef string `json:"resource_space_ref"`
|
||||
CodeRepoURL string `json:"code_repo_url"`
|
||||
CodeRepoType enum.GitspaceCodeRepoType `json:"code_repo_type"`
|
||||
CodeRepoRef *string `json:"code_repo_ref"`
|
||||
Branch string `json:"branch"`
|
||||
DevcontainerPath *string `json:"devcontainer_path"`
|
||||
Metadata map[string]string `json:"metadata"`
|
||||
SSHTokenIdentifier string `json:"ssh_token_identifier"`
|
||||
AIAgents []enum.AIAgent `json:"ai_agents"`
|
||||
}
|
||||
|
||||
// Create creates a new gitspace.
|
||||
func (c *Controller) Create(
|
||||
ctx context.Context,
|
||||
session *auth.Session,
|
||||
in *CreateInput,
|
||||
) (*types.GitspaceConfig, error) {
|
||||
space, err := c.spaceFinder.FindByRef(ctx, in.SpaceRef)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to find parent by ref: %w", err)
|
||||
}
|
||||
if err = c.sanitizeCreateInput(in); err != nil {
|
||||
return nil, fmt.Errorf("invalid input: %w", err)
|
||||
}
|
||||
if err = apiauth.CheckGitspace(
|
||||
ctx,
|
||||
c.authorizer,
|
||||
session,
|
||||
space.Path,
|
||||
"",
|
||||
enum.PermissionGitspaceCreate); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// check if it's an internal repo
|
||||
if in.CodeRepoType == enum.CodeRepoTypeGitness && *in.CodeRepoRef != "" {
|
||||
repo, err := c.repoFinder.FindByRef(ctx, *in.CodeRepoRef)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("couldn't fetch repo for the user: %w", err)
|
||||
}
|
||||
if err = apiauth.CheckRepo(
|
||||
ctx,
|
||||
c.authorizer,
|
||||
session,
|
||||
repo,
|
||||
enum.PermissionRepoView); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
identifier, err := buildIdentifier(in.Identifier)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not generate identifier for gitspace config : %q %w", in.Identifier, err)
|
||||
}
|
||||
now := time.Now().UnixMilli()
|
||||
var gitspaceConfig *types.GitspaceConfig
|
||||
// assume resource to be in same space if it's not explicitly specified.
|
||||
if in.ResourceSpaceRef == "" {
|
||||
rootSpaceRef, _, err := paths.DisectRoot(in.SpaceRef)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to find root space path for %s: %w", in.SpaceRef, err)
|
||||
}
|
||||
in.ResourceSpaceRef = rootSpaceRef
|
||||
}
|
||||
resourceIdentifier := in.ResourceIdentifier
|
||||
resourceSpace, err := c.spaceFinder.FindByRef(ctx, in.ResourceSpaceRef)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to find parent by ref: %w", err)
|
||||
}
|
||||
if err = apiauth.CheckInfraProvider(
|
||||
ctx,
|
||||
c.authorizer,
|
||||
session,
|
||||
resourceSpace.Path,
|
||||
"",
|
||||
enum.PermissionInfraProviderView); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// TODO: Temp fix to ensure the gitspace creation doesnt fail. Once the FE starts sending this field in the
|
||||
// request, remove this.
|
||||
if in.InfraProviderConfigIdentifier == "" {
|
||||
in.InfraProviderConfigIdentifier = defaultResourceIdentifier
|
||||
}
|
||||
|
||||
infraProviderResource, err := c.createOrFindInfraProviderResource(ctx, resourceSpace, resourceIdentifier,
|
||||
in.InfraProviderConfigIdentifier, now)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = c.gitspaceLimiter.Usage(ctx, space.ID, infraProviderResource.InfraProviderType)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = c.tx.WithTx(ctx, func(ctx context.Context) error {
|
||||
codeRepo := types.CodeRepo{
|
||||
URL: in.CodeRepoURL,
|
||||
Ref: in.CodeRepoRef,
|
||||
Type: in.CodeRepoType,
|
||||
Branch: in.Branch,
|
||||
DevcontainerPath: in.DevcontainerPath,
|
||||
}
|
||||
|
||||
principal := session.Principal
|
||||
principalID := principal.ID
|
||||
user := types.GitspaceUser{
|
||||
Identifier: principal.UID,
|
||||
Email: principal.Email,
|
||||
DisplayName: principal.DisplayName,
|
||||
ID: &principalID}
|
||||
gitspaceConfig = &types.GitspaceConfig{
|
||||
Identifier: identifier,
|
||||
Name: in.Name,
|
||||
IDE: in.IDE,
|
||||
State: enum.GitspaceStateUninitialized,
|
||||
SpaceID: space.ID,
|
||||
SpacePath: space.Path,
|
||||
Created: now,
|
||||
Updated: now,
|
||||
SSHTokenIdentifier: in.SSHTokenIdentifier,
|
||||
AIAgents: in.AIAgents,
|
||||
CodeRepo: codeRepo,
|
||||
GitspaceUser: user,
|
||||
}
|
||||
gitspaceConfig.InfraProviderResource = *infraProviderResource
|
||||
|
||||
if err = c.settingsService.ValidateGitspaceConfigCreate(
|
||||
ctx, *infraProviderResource, *gitspaceConfig); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = c.gitspaceSvc.Create(ctx, gitspaceConfig)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create gitspace config for : %q %w", identifier, err)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
gitspaceConfig.BranchURL = c.gitspaceSvc.GetBranchURL(ctx, gitspaceConfig)
|
||||
return gitspaceConfig, nil
|
||||
}
|
||||
|
||||
func (c *Controller) createOrFindInfraProviderResource(
|
||||
ctx context.Context,
|
||||
resourceSpace *types.SpaceCore,
|
||||
resourceIdentifier string,
|
||||
infraProviderConfigIdentifier string,
|
||||
now int64,
|
||||
) (*types.InfraProviderResource, error) {
|
||||
var resource *types.InfraProviderResource
|
||||
var err error
|
||||
|
||||
resource, err = c.infraProviderSvc.FindResourceByConfigAndIdentifier(ctx, resourceSpace.ID,
|
||||
infraProviderConfigIdentifier, resourceIdentifier)
|
||||
if ((err != nil && errors.Is(err, store.ErrResourceNotFound)) || resource == nil) &&
|
||||
resourceIdentifier == defaultResourceIdentifier {
|
||||
resource, err = c.autoCreateDefaultResource(ctx, resourceSpace, now)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else if err != nil {
|
||||
return nil, fmt.Errorf("could not find infra provider resource : %q %w", resourceIdentifier, err)
|
||||
}
|
||||
|
||||
return resource, err
|
||||
}
|
||||
|
||||
func (c *Controller) autoCreateDefaultResource(
|
||||
ctx context.Context,
|
||||
currentSpace *types.SpaceCore,
|
||||
now int64,
|
||||
) (*types.InfraProviderResource, error) {
|
||||
rootSpace, err := c.spaceStore.GetRootSpace(ctx, currentSpace.ID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not get root space for space %s while autocreating default docker "+
|
||||
"resource: %w", currentSpace.Path, err)
|
||||
}
|
||||
|
||||
defaultDockerConfig := &types.InfraProviderConfig{
|
||||
Identifier: defaultResourceIdentifier,
|
||||
Name: "default docker infrastructure",
|
||||
Type: enum.InfraProviderTypeDocker,
|
||||
SpaceID: rootSpace.ID,
|
||||
SpacePath: rootSpace.Path,
|
||||
Created: now,
|
||||
Updated: now,
|
||||
}
|
||||
defaultResource := types.InfraProviderResource{
|
||||
UID: defaultResourceIdentifier,
|
||||
Name: "Standard Docker Resource",
|
||||
InfraProviderConfigIdentifier: defaultDockerConfig.Identifier,
|
||||
InfraProviderType: enum.InfraProviderTypeDocker,
|
||||
CPU: wrapString("any"),
|
||||
Memory: wrapString("any"),
|
||||
Disk: wrapString("any"),
|
||||
Network: wrapString("standard"),
|
||||
SpaceID: rootSpace.ID,
|
||||
SpacePath: rootSpace.Path,
|
||||
Created: now,
|
||||
Updated: now,
|
||||
}
|
||||
defaultDockerConfig.Resources = []types.InfraProviderResource{defaultResource}
|
||||
|
||||
err = c.infraProviderSvc.CreateConfigAndResources(ctx, defaultDockerConfig)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not auto-create the infra provider: %w", err)
|
||||
}
|
||||
|
||||
resource, err := c.infraProviderSvc.FindResourceByConfigAndIdentifier(ctx, rootSpace.ID,
|
||||
defaultDockerConfig.Identifier, defaultResourceIdentifier)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not find infra provider resource : %q %w", defaultResourceIdentifier, err)
|
||||
}
|
||||
|
||||
return resource, nil
|
||||
}
|
||||
|
||||
func wrapString(str string) *string {
|
||||
return &str
|
||||
}
|
||||
|
||||
func (c *Controller) sanitizeCreateInput(in *CreateInput) error {
|
||||
if err := check.Identifier(in.ResourceIdentifier); err != nil {
|
||||
return err
|
||||
}
|
||||
parentRefAsID, err := strconv.ParseInt(in.SpaceRef, 10, 64)
|
||||
if (err == nil && parentRefAsID <= 0) || (len(strings.TrimSpace(in.SpaceRef)) == 0) {
|
||||
return ErrGitspaceRequiresParent
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func buildIdentifier(identifier string) (string, error) {
|
||||
toLower := strings.ToLower(identifier)
|
||||
|
||||
err := validateIdentifier(toLower)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
suffixUID, err := gonanoid.Generate(gitspace.AllowedUIDAlphabet, suffixLen)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("could not generate UID for gitspace config: %q %w", toLower, err)
|
||||
}
|
||||
|
||||
return toLower + "-" + suffixUID, nil
|
||||
}
|
||||
|
||||
func validateIdentifier(identifier string) error {
|
||||
invalidCharPattern := regexp.MustCompile(`[^a-z0-9-]`)
|
||||
if invalidCharPattern.MatchString(identifier) {
|
||||
return usererror.BadRequestf("Identifier %q contains invalid characters: only lowercase letters, "+
|
||||
"digits, and hyphens are allowed", identifier)
|
||||
}
|
||||
|
||||
if len(identifier) > maxGitspaceConfigIdentifierPrefixLength {
|
||||
return fmt.Errorf("identifier %q length should be upto 50 characters, is %d characters",
|
||||
identifier, len(identifier))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
@ -1,38 +0,0 @@
|
|||
// Copyright 2023 Harness, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package gitspace
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
apiauth "github.com/harness/gitness/app/api/auth"
|
||||
"github.com/harness/gitness/app/auth"
|
||||
"github.com/harness/gitness/types/enum"
|
||||
)
|
||||
|
||||
func (c *Controller) Delete(
|
||||
ctx context.Context,
|
||||
session *auth.Session,
|
||||
spaceRef string,
|
||||
identifier string,
|
||||
) error {
|
||||
err := apiauth.CheckGitspace(ctx, c.authorizer, session, spaceRef, identifier, enum.PermissionGitspaceDelete)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to authorize: %w", err)
|
||||
}
|
||||
|
||||
return c.gitspaceSvc.DeleteGitspaceByIdentifier(ctx, spaceRef, identifier)
|
||||
}
|
||||
|
|
@ -1,81 +0,0 @@
|
|||
// Copyright 2023 Harness, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package gitspace
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
apiauth "github.com/harness/gitness/app/api/auth"
|
||||
"github.com/harness/gitness/app/auth"
|
||||
"github.com/harness/gitness/types"
|
||||
"github.com/harness/gitness/types/enum"
|
||||
)
|
||||
|
||||
var eventMessageMap map[enum.GitspaceEventType]string
|
||||
|
||||
func init() {
|
||||
eventMessageMap = enum.EventsMessageMapping()
|
||||
}
|
||||
|
||||
func (c *Controller) Events(
|
||||
ctx context.Context,
|
||||
session *auth.Session,
|
||||
spaceRef string,
|
||||
identifier string,
|
||||
page int,
|
||||
limit int,
|
||||
) ([]*types.GitspaceEventResponse, int, error) {
|
||||
space, err := c.spaceFinder.FindByRef(ctx, spaceRef)
|
||||
if err != nil {
|
||||
return nil, 0, fmt.Errorf("failed to find space: %w", err)
|
||||
}
|
||||
|
||||
err = apiauth.CheckGitspace(ctx, c.authorizer, session, space.Path, identifier, enum.PermissionGitspaceView)
|
||||
if err != nil {
|
||||
return nil, 0, fmt.Errorf("failed to authorize: %w", err)
|
||||
}
|
||||
|
||||
pagination := types.Pagination{
|
||||
Page: page,
|
||||
Size: limit,
|
||||
}
|
||||
skipEvents := []enum.GitspaceEventType{
|
||||
enum.GitspaceEventTypeInfraCleanupStart,
|
||||
enum.GitspaceEventTypeInfraCleanupCompleted,
|
||||
enum.GitspaceEventTypeInfraCleanupFailed,
|
||||
}
|
||||
filter := &types.GitspaceEventFilter{
|
||||
Pagination: pagination,
|
||||
QueryKey: identifier,
|
||||
SkipEvents: skipEvents,
|
||||
}
|
||||
events, count, err := c.gitspaceEventStore.List(ctx, filter)
|
||||
if err != nil {
|
||||
return nil, 0, fmt.Errorf("failed to list gitspace events for identifier %s: %w", identifier, err)
|
||||
}
|
||||
|
||||
var result = make([]*types.GitspaceEventResponse, len(events))
|
||||
for index, event := range events {
|
||||
gitspaceEventResponse := &types.GitspaceEventResponse{
|
||||
GitspaceEvent: *event,
|
||||
Message: eventMessageMap[event.Event],
|
||||
EventTime: time.Unix(0, event.Timestamp).Format(time.RFC3339Nano)}
|
||||
result[index] = gitspaceEventResponse
|
||||
}
|
||||
|
||||
return result, count, nil
|
||||
}
|
||||
|
|
@ -1,43 +0,0 @@
|
|||
// Copyright 2023 Harness, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package gitspace
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
apiauth "github.com/harness/gitness/app/api/auth"
|
||||
"github.com/harness/gitness/app/auth"
|
||||
"github.com/harness/gitness/types"
|
||||
"github.com/harness/gitness/types/enum"
|
||||
)
|
||||
|
||||
func (c *Controller) Find(
|
||||
ctx context.Context,
|
||||
session *auth.Session,
|
||||
spaceRef string,
|
||||
identifier string,
|
||||
) (*types.GitspaceConfig, error) {
|
||||
err := apiauth.CheckGitspace(ctx, c.authorizer, session, spaceRef, identifier, enum.PermissionGitspaceView)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to authorize: %w", err)
|
||||
}
|
||||
|
||||
res, err := c.gitspaceSvc.FindWithLatestInstanceWithSpacePath(ctx, spaceRef, identifier)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to find gitspace: %w", err)
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
|
|
@ -1,42 +0,0 @@
|
|||
// Copyright 2023 Harness, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package gitspace
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/harness/gitness/app/auth"
|
||||
"github.com/harness/gitness/types"
|
||||
)
|
||||
|
||||
func (c *Controller) FindAllInSameScope(
|
||||
ctx context.Context,
|
||||
// todo: integrate with access control.
|
||||
_ *auth.Session,
|
||||
spaceRef string,
|
||||
identifiers []string,
|
||||
) ([]types.GitspaceConfig, error) {
|
||||
space, err := c.spaceFinder.FindByRef(ctx, spaceRef)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to find space: %w", err)
|
||||
}
|
||||
gitspaceConfigs, err := c.gitspaceSvc.FindAllByIdentifier(ctx, space.ID, identifiers)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to find gitspaces: %w", err)
|
||||
}
|
||||
|
||||
return gitspaceConfigs, nil
|
||||
}
|
||||
|
|
@ -1,146 +0,0 @@
|
|||
// Copyright 2023 Harness, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package gitspace
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
apiauth "github.com/harness/gitness/app/api/auth"
|
||||
"github.com/harness/gitness/app/auth"
|
||||
"github.com/harness/gitness/store"
|
||||
"github.com/harness/gitness/store/database/dbtx"
|
||||
"github.com/harness/gitness/types"
|
||||
"github.com/harness/gitness/types/enum"
|
||||
)
|
||||
|
||||
// ListAllGitspaces all the gitspace with given filter.
|
||||
// DO NOT USE allSpaceIDs = true for cde-manager. This arg is used only in gitness to list all the gitspaces in gitness
|
||||
// for all. This is useful to list all the gitspaces in OSS for IDE plugins.
|
||||
func (c *Controller) ListAllGitspaces( // nolint:gocognit
|
||||
ctx context.Context,
|
||||
session *auth.Session,
|
||||
filter types.GitspaceFilter,
|
||||
allSpaceIDs bool,
|
||||
) ([]*types.GitspaceConfig, error) {
|
||||
if allSpaceIDs {
|
||||
leafSpaceIDs, err := c.fetchAllLeafSpaceIDs(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
filter.SpaceIDs = leafSpaceIDs
|
||||
}
|
||||
var result []*types.GitspaceConfig
|
||||
err := c.tx.WithTx(ctx, func(ctx context.Context) (err error) {
|
||||
allGitspaceConfigs, _, _, err := c.gitspaceSvc.ListGitspacesWithInstance(ctx, filter, false)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to list gitspace configs: %w", err)
|
||||
}
|
||||
|
||||
var spacesMap = make(map[int64]string)
|
||||
for idx := range allGitspaceConfigs {
|
||||
if spacesMap[allGitspaceConfigs[idx].SpaceID] == "" {
|
||||
space, findSpaceErr := c.spaceFinder.FindByRef(ctx, allGitspaceConfigs[idx].SpacePath)
|
||||
if findSpaceErr != nil {
|
||||
if !errors.Is(findSpaceErr, store.ErrResourceNotFound) {
|
||||
return fmt.Errorf(
|
||||
"error fetching space %d: %w", allGitspaceConfigs[idx].SpaceID, findSpaceErr)
|
||||
}
|
||||
continue
|
||||
}
|
||||
spacesMap[allGitspaceConfigs[idx].SpaceID] = space.Path
|
||||
}
|
||||
}
|
||||
|
||||
authorizedSpaceIDs, err := c.getAuthorizedSpaces(ctx, session, spacesMap)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
finalGitspaceConfigs := c.filter(allGitspaceConfigs, authorizedSpaceIDs)
|
||||
|
||||
result = finalGitspaceConfigs
|
||||
|
||||
return nil
|
||||
}, dbtx.TxDefaultReadOnly)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (c *Controller) fetchAllLeafSpaceIDs(ctx context.Context) ([]int64, error) {
|
||||
opts := &types.SpaceFilter{}
|
||||
rootSpaces, err := c.spaceStore.GetAllRootSpaces(ctx, opts)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get root spaces: %w", err)
|
||||
}
|
||||
var leafSpaceIDs []int64
|
||||
for _, rootSpace := range rootSpaces {
|
||||
spaceIDs, err := c.spaceStore.GetDescendantsIDs(ctx, rootSpace.ID)
|
||||
if err != nil {
|
||||
if !errors.Is(err, store.ErrResourceNotFound) {
|
||||
return nil, fmt.Errorf("failed to get descendants ids: %w", err)
|
||||
}
|
||||
}
|
||||
leafSpaceIDs = append(leafSpaceIDs, spaceIDs...)
|
||||
}
|
||||
|
||||
return leafSpaceIDs, nil
|
||||
}
|
||||
|
||||
func (c *Controller) filter(
|
||||
allGitspaceConfigs []*types.GitspaceConfig,
|
||||
authorizedSpaceIDs map[int64]bool,
|
||||
) []*types.GitspaceConfig {
|
||||
return c.getAuthorizedGitspaceConfigs(allGitspaceConfigs, authorizedSpaceIDs)
|
||||
}
|
||||
|
||||
func (c *Controller) getAuthorizedGitspaceConfigs(
|
||||
allGitspaceConfigs []*types.GitspaceConfig,
|
||||
authorizedSpaceIDs map[int64]bool,
|
||||
) []*types.GitspaceConfig {
|
||||
var authorizedGitspaceConfigs = make([]*types.GitspaceConfig, 0)
|
||||
for idx := range allGitspaceConfigs {
|
||||
if authorizedSpaceIDs[allGitspaceConfigs[idx].SpaceID] {
|
||||
authorizedGitspaceConfigs = append(authorizedGitspaceConfigs, allGitspaceConfigs[idx])
|
||||
}
|
||||
}
|
||||
return authorizedGitspaceConfigs
|
||||
}
|
||||
|
||||
func (c *Controller) getAuthorizedSpaces(
|
||||
ctx context.Context,
|
||||
session *auth.Session,
|
||||
spacesMap map[int64]string,
|
||||
) (map[int64]bool, error) {
|
||||
var authorizedSpaceIDs = make(map[int64]bool, 0)
|
||||
|
||||
for spaceID, spacePath := range spacesMap {
|
||||
err := apiauth.CheckGitspace(
|
||||
ctx, c.authorizer, session, spacePath, "", enum.PermissionGitspaceView,
|
||||
)
|
||||
if err != nil && !apiauth.IsNoAccess(err) {
|
||||
return nil, fmt.Errorf("failed to check gitspace auth for space ID %d: %w", spaceID, err)
|
||||
}
|
||||
|
||||
authorizedSpaceIDs[spaceID] = true
|
||||
}
|
||||
|
||||
return authorizedSpaceIDs, nil
|
||||
}
|
||||
|
|
@ -1,86 +0,0 @@
|
|||
// Copyright 2023 Harness, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package gitspace
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
apiauth "github.com/harness/gitness/app/api/auth"
|
||||
"github.com/harness/gitness/app/auth"
|
||||
"github.com/harness/gitness/app/sse"
|
||||
"github.com/harness/gitness/livelog"
|
||||
"github.com/harness/gitness/types/enum"
|
||||
)
|
||||
|
||||
func (c *Controller) LogsStream(
|
||||
ctx context.Context,
|
||||
session *auth.Session,
|
||||
spaceRef string,
|
||||
identifier string,
|
||||
) (<-chan *sse.Event, <-chan error, error) {
|
||||
err := apiauth.CheckGitspace(ctx, c.authorizer, session, spaceRef, identifier, enum.PermissionGitspaceView)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("failed to authorize: %w", err)
|
||||
}
|
||||
|
||||
gitspaceConfig, err := c.gitspaceSvc.FindWithLatestInstanceWithSpacePath(ctx, spaceRef, identifier)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("failed to find gitspace config: %w", err)
|
||||
}
|
||||
|
||||
linec, errc := c.statefulLogger.TailLogStream(ctx, gitspaceConfig.ID)
|
||||
|
||||
if linec == nil {
|
||||
return nil, nil, fmt.Errorf("log stream not present, failed to tail log stream")
|
||||
}
|
||||
|
||||
evenc := make(chan *sse.Event)
|
||||
errch := make(chan error)
|
||||
|
||||
go func() {
|
||||
defer close(evenc)
|
||||
defer close(errch)
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return
|
||||
case line, ok := <-linec:
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
event := sse.Event{
|
||||
Type: enum.SSETypeLogLineAppended,
|
||||
Data: marshalLine(line),
|
||||
}
|
||||
evenc <- &event
|
||||
case err = <-errc:
|
||||
if err != nil {
|
||||
errch <- err
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
return evenc, errch, nil
|
||||
}
|
||||
|
||||
func marshalLine(line *livelog.Line) []byte {
|
||||
data, _ := json.Marshal(line)
|
||||
return data
|
||||
}
|
||||
|
|
@ -1,89 +0,0 @@
|
|||
// Copyright 2023 Harness, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package gitspace
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/url"
|
||||
|
||||
apiauth "github.com/harness/gitness/app/api/auth"
|
||||
"github.com/harness/gitness/app/api/usererror"
|
||||
"github.com/harness/gitness/app/auth"
|
||||
"github.com/harness/gitness/app/gitspace/scm"
|
||||
"github.com/harness/gitness/types/enum"
|
||||
)
|
||||
|
||||
type LookupRepoInput struct {
|
||||
SpaceRef string `json:"space_ref"` // Ref of the parent space
|
||||
URL string `json:"url"`
|
||||
RepoType enum.GitspaceCodeRepoType `json:"repo_type"`
|
||||
}
|
||||
|
||||
var (
|
||||
ErrInvalidURL = usererror.BadRequest(
|
||||
"The URL specified is not valid format.")
|
||||
ErrRepoMissing = usererror.BadRequest(
|
||||
"There must be URL or Ref specified fir repo.")
|
||||
ErrBadURLScheme = usererror.BadRequest("The URL is missing scheme, it must start with http or https")
|
||||
)
|
||||
|
||||
func (c *Controller) LookupRepo(
|
||||
ctx context.Context,
|
||||
session *auth.Session,
|
||||
in *LookupRepoInput,
|
||||
) (*scm.CodeRepositoryResponse, error) {
|
||||
if err := c.sanitizeLookupRepoInput(in); err != nil {
|
||||
return nil, fmt.Errorf("invalid input: %w", err)
|
||||
}
|
||||
space, err := c.spaceFinder.FindByRef(ctx, in.SpaceRef)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to find space: %w", err)
|
||||
}
|
||||
err = apiauth.CheckInfraProvider(ctx, c.authorizer, session, space.Path,
|
||||
"", enum.PermissionInfraProviderView)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to authorize: %w", err)
|
||||
}
|
||||
repositoryRequest := scm.CodeRepositoryRequest{
|
||||
URL: in.URL,
|
||||
UserIdentifier: session.Principal.UID,
|
||||
SpacePath: space.Path,
|
||||
RepoType: in.RepoType,
|
||||
UserID: session.Principal.ID,
|
||||
}
|
||||
codeRepositoryResponse, err := c.scm.CheckValidCodeRepo(ctx, repositoryRequest)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return codeRepositoryResponse, nil
|
||||
}
|
||||
|
||||
func (c *Controller) sanitizeLookupRepoInput(in *LookupRepoInput) error {
|
||||
if in.RepoType == "" && in.URL == "" {
|
||||
return ErrRepoMissing
|
||||
}
|
||||
parsedURL, err := url.Parse(in.URL)
|
||||
if err != nil {
|
||||
return ErrInvalidURL
|
||||
}
|
||||
if parsedURL.Scheme == "" {
|
||||
return ErrBadURLScheme
|
||||
}
|
||||
if _, err := url.ParseRequestURI(parsedURL.RequestURI()); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
@ -1,225 +0,0 @@
|
|||
// Copyright 2023 Harness, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package gitspace
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
apiauth "github.com/harness/gitness/app/api/auth"
|
||||
"github.com/harness/gitness/app/api/controller/gitspace/common"
|
||||
"github.com/harness/gitness/app/api/usererror"
|
||||
"github.com/harness/gitness/app/auth"
|
||||
"github.com/harness/gitness/app/paths"
|
||||
gitnessTypes "github.com/harness/gitness/types"
|
||||
"github.com/harness/gitness/types/check"
|
||||
"github.com/harness/gitness/types/enum"
|
||||
)
|
||||
|
||||
// UpdateInput is used for updating a gitspace.
|
||||
type UpdateInput struct {
|
||||
IDE enum.IDEType `json:"ide"`
|
||||
ResourceIdentifier string `json:"resource_identifier"`
|
||||
ResourceSpaceRef string `json:"resource_space_ref"`
|
||||
Name string `json:"name"`
|
||||
SSHTokenIdentifier string `json:"ssh_token_identifier"`
|
||||
Identifier string `json:"-"`
|
||||
SpaceRef string `json:"-"`
|
||||
}
|
||||
|
||||
func (c *Controller) Update(
|
||||
ctx context.Context,
|
||||
session *auth.Session,
|
||||
spaceRef string,
|
||||
identifier string,
|
||||
in *UpdateInput,
|
||||
) (*gitnessTypes.GitspaceConfig, error) {
|
||||
in.SpaceRef = spaceRef
|
||||
in.Identifier = identifier
|
||||
if err := c.sanitizeUpdateInput(in); err != nil {
|
||||
return nil, fmt.Errorf("failed to sanitize input: %w", err)
|
||||
}
|
||||
err := apiauth.CheckGitspace(ctx, c.authorizer, session, spaceRef, identifier, enum.PermissionGitspaceEdit)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to authorize: %w", err)
|
||||
}
|
||||
|
||||
gitspaceConfig, err := c.gitspaceSvc.FindWithLatestInstanceWithSpacePath(ctx, spaceRef, identifier)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to find gitspace config: %w", err)
|
||||
}
|
||||
|
||||
// Check the gitspace state. Update can be done only in stopped, error or uninitialized state
|
||||
currentState := gitspaceConfig.State
|
||||
if currentState != enum.GitspaceStateStopped &&
|
||||
currentState != enum.GitspaceStateUninitialized {
|
||||
return nil, usererror.BadRequest(
|
||||
"Gitspace update can only be performed when gitspace is stopped or uninitialized",
|
||||
)
|
||||
}
|
||||
|
||||
c.updateIDE(in, gitspaceConfig)
|
||||
if err := c.handleSSHToken(in, gitspaceConfig); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := c.updateResourceIdentifier(ctx, in, gitspaceConfig); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// TODO Update with proper locks
|
||||
err = c.gitspaceSvc.UpdateConfig(ctx, gitspaceConfig)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to update gitspace config: %w", err)
|
||||
}
|
||||
return gitspaceConfig, nil
|
||||
}
|
||||
|
||||
func (c *Controller) updateIDE(in *UpdateInput, gitspaceConfig *gitnessTypes.GitspaceConfig) {
|
||||
if in.IDE != "" && in.IDE != gitspaceConfig.IDE {
|
||||
gitspaceConfig.IDE = in.IDE
|
||||
gitspaceConfig.IsMarkedForReset = true
|
||||
}
|
||||
|
||||
// Always clear SSH token if IDE is VS Code Web
|
||||
if gitspaceConfig.IDE == enum.IDETypeVSCodeWeb {
|
||||
gitspaceConfig.SSHTokenIdentifier = ""
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Controller) handleSSHToken(in *UpdateInput, gitspaceConfig *gitnessTypes.GitspaceConfig) error {
|
||||
if in.SSHTokenIdentifier != "" {
|
||||
if gitspaceConfig.IDE == enum.IDETypeVSCodeWeb {
|
||||
return usererror.BadRequest("SSH token should not be sent with VS Code Web IDE")
|
||||
}
|
||||
|
||||
// For other IDEs, update the token
|
||||
if in.SSHTokenIdentifier != gitspaceConfig.SSHTokenIdentifier {
|
||||
gitspaceConfig.SSHTokenIdentifier = in.SSHTokenIdentifier
|
||||
gitspaceConfig.IsMarkedForReset = true
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Controller) updateResourceIdentifier(
|
||||
ctx context.Context,
|
||||
in *UpdateInput,
|
||||
gitspaceConfig *gitnessTypes.GitspaceConfig,
|
||||
) error {
|
||||
// Handle resource identifier update similar to create, but only if provided
|
||||
if in.ResourceIdentifier == "" || in.ResourceIdentifier == gitspaceConfig.InfraProviderResource.UID {
|
||||
return nil
|
||||
}
|
||||
|
||||
if gitspaceConfig.InfraProviderResource.UID == "default" {
|
||||
return usererror.BadRequest("The default resource cannot be updated in harness open source")
|
||||
}
|
||||
|
||||
// Set resource space reference if not provided
|
||||
if in.ResourceSpaceRef == "" {
|
||||
rootSpaceRef, _, err := paths.DisectRoot(in.SpaceRef)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to find root space path for %s: %w", in.SpaceRef, err)
|
||||
}
|
||||
in.ResourceSpaceRef = rootSpaceRef
|
||||
}
|
||||
|
||||
// Find spaces and resources
|
||||
existingResource, newResource, err := c.getResources(ctx, in, gitspaceConfig)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Validate the resource spec change
|
||||
markForInfraReset, err := common.IsResourceSpecChangeAllowed(existingResource, newResource)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
gitspaceConfig.IsMarkedForInfraReset = gitspaceConfig.IsMarkedForInfraReset || markForInfraReset
|
||||
gitspaceConfig.InfraProviderResource = *newResource
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Controller) getResources(
|
||||
ctx context.Context,
|
||||
in *UpdateInput,
|
||||
gitspaceConfig *gitnessTypes.GitspaceConfig,
|
||||
) (*gitnessTypes.InfraProviderResource, *gitnessTypes.InfraProviderResource, error) {
|
||||
// Get existing resource space and resource
|
||||
existingSpace, err := c.spaceFinder.FindByRef(
|
||||
ctx,
|
||||
gitspaceConfig.InfraProviderResource.SpacePath,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("failed to find resource space: %w", err)
|
||||
}
|
||||
|
||||
existingResource, err := c.infraProviderSvc.FindResourceByConfigAndIdentifier(
|
||||
ctx,
|
||||
existingSpace.ID,
|
||||
gitspaceConfig.InfraProviderResource.InfraProviderConfigIdentifier,
|
||||
gitspaceConfig.InfraProviderResource.UID,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf(
|
||||
"could not find existing infra provider resource: %w",
|
||||
err,
|
||||
)
|
||||
}
|
||||
|
||||
// Get new resource space and resource
|
||||
newSpace, err := c.spaceFinder.FindByRef(
|
||||
ctx,
|
||||
in.ResourceSpaceRef,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("failed to find resource space: %w", err)
|
||||
}
|
||||
|
||||
newResource, err := c.infraProviderSvc.FindResourceByConfigAndIdentifier(
|
||||
ctx,
|
||||
newSpace.ID,
|
||||
gitspaceConfig.InfraProviderResource.InfraProviderConfigIdentifier,
|
||||
in.ResourceIdentifier,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf(
|
||||
"could not find infra provider resource %q: %w",
|
||||
in.ResourceIdentifier,
|
||||
err,
|
||||
)
|
||||
}
|
||||
|
||||
return existingResource, newResource, nil
|
||||
}
|
||||
|
||||
func (c *Controller) sanitizeUpdateInput(in *UpdateInput) error {
|
||||
parentRefAsID, err := strconv.ParseInt(in.SpaceRef, 10, 64)
|
||||
if (err == nil && parentRefAsID <= 0) || (len(strings.TrimSpace(in.SpaceRef)) == 0) {
|
||||
return ErrGitspaceRequiresParent
|
||||
}
|
||||
|
||||
//nolint:revive
|
||||
if err := check.Identifier(in.Identifier); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
@ -1,65 +0,0 @@
|
|||
// Copyright 2023 Harness, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package gitspace
|
||||
|
||||
import (
|
||||
"github.com/harness/gitness/app/api/controller/limiter"
|
||||
"github.com/harness/gitness/app/auth/authz"
|
||||
"github.com/harness/gitness/app/gitspace/logutil"
|
||||
"github.com/harness/gitness/app/gitspace/scm"
|
||||
"github.com/harness/gitness/app/services/gitspace"
|
||||
"github.com/harness/gitness/app/services/gitspacesettings"
|
||||
"github.com/harness/gitness/app/services/infraprovider"
|
||||
"github.com/harness/gitness/app/services/refcache"
|
||||
"github.com/harness/gitness/app/store"
|
||||
"github.com/harness/gitness/store/database/dbtx"
|
||||
|
||||
"github.com/google/wire"
|
||||
)
|
||||
|
||||
// WireSet provides a wire set for this package.
|
||||
var WireSet = wire.NewSet(
|
||||
ProvideController,
|
||||
)
|
||||
|
||||
func ProvideController(
|
||||
tx dbtx.Transactor,
|
||||
authorizer authz.Authorizer,
|
||||
infraProviderSvc *infraprovider.Service,
|
||||
spaceStore store.SpaceStore,
|
||||
spaceFinder refcache.SpaceFinder,
|
||||
eventStore store.GitspaceEventStore,
|
||||
statefulLogger *logutil.StatefulLogger,
|
||||
scm *scm.SCM,
|
||||
gitspaceSvc *gitspace.Service,
|
||||
gitspaceLimiter limiter.Gitspace,
|
||||
repoFinder refcache.RepoFinder,
|
||||
settingsService gitspacesettings.Service,
|
||||
) *Controller {
|
||||
return NewController(
|
||||
tx,
|
||||
authorizer,
|
||||
infraProviderSvc,
|
||||
spaceStore,
|
||||
spaceFinder,
|
||||
eventStore,
|
||||
statefulLogger,
|
||||
scm,
|
||||
gitspaceSvc,
|
||||
gitspaceLimiter,
|
||||
repoFinder,
|
||||
settingsService,
|
||||
)
|
||||
}
|
||||
|
|
@ -1,75 +0,0 @@
|
|||
// Copyright 2023 Harness, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package infraprovider
|
||||
|
||||
import (
|
||||
"github.com/harness/gitness/app/auth/authz"
|
||||
"github.com/harness/gitness/app/services/infraprovider"
|
||||
"github.com/harness/gitness/app/services/refcache"
|
||||
"github.com/harness/gitness/types/enum"
|
||||
)
|
||||
|
||||
const NoResourceIdentifier = ""
|
||||
|
||||
type ConfigInput struct {
|
||||
Identifier string `json:"identifier" yaml:"identifier"`
|
||||
SpaceRef string `json:"space_ref" yaml:"space_ref"`
|
||||
Name string `json:"name" yaml:"name"`
|
||||
Type enum.InfraProviderType `json:"type" yaml:"type"`
|
||||
Metadata map[string]any `json:"metadata" yaml:"metadata"`
|
||||
}
|
||||
|
||||
type ResourceInput struct {
|
||||
Identifier string `json:"identifier" yaml:"identifier"`
|
||||
Name string `json:"name" yaml:"name"`
|
||||
InfraProviderType enum.InfraProviderType `json:"infra_provider_type" yaml:"infra_provider_type"`
|
||||
CPU *string `json:"cpu" yaml:"cpu"`
|
||||
Memory *string `json:"memory" yaml:"memory"`
|
||||
Disk *string `json:"disk" yaml:"disk"`
|
||||
Network *string `json:"network" yaml:"network"`
|
||||
Region string `json:"region" yaml:"region"`
|
||||
Metadata map[string]string `json:"metadata" yaml:"metadata"`
|
||||
GatewayHost *string `json:"gateway_host" yaml:"gateway_host"`
|
||||
GatewayPort *string `json:"gateway_port" yaml:"gateway_port"`
|
||||
}
|
||||
|
||||
type AutoCreateInput struct {
|
||||
Config ConfigInput `json:"config" yaml:"config"`
|
||||
Resources []ResourceInput `json:"resources" yaml:"resources"`
|
||||
}
|
||||
|
||||
type TemplateInput struct {
|
||||
Identifier string `json:"identifier" yaml:"identifier"`
|
||||
Description string `json:"description" yaml:"description"`
|
||||
Data string `json:"data" yaml:"data"`
|
||||
}
|
||||
|
||||
type Controller struct {
|
||||
authorizer authz.Authorizer
|
||||
spaceFinder refcache.SpaceFinder
|
||||
infraproviderSvc *infraprovider.Service
|
||||
}
|
||||
|
||||
func NewController(
|
||||
authorizer authz.Authorizer,
|
||||
spaceFinder refcache.SpaceFinder,
|
||||
infraproviderSvc *infraprovider.Service,
|
||||
) *Controller {
|
||||
return &Controller{
|
||||
authorizer: authorizer,
|
||||
spaceFinder: spaceFinder,
|
||||
infraproviderSvc: infraproviderSvc,
|
||||
}
|
||||
}
|
||||
|
|
@ -1,83 +0,0 @@
|
|||
// Copyright 2023 Harness, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package infraprovider
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
apiauth "github.com/harness/gitness/app/api/auth"
|
||||
"github.com/harness/gitness/app/auth"
|
||||
"github.com/harness/gitness/types"
|
||||
"github.com/harness/gitness/types/check"
|
||||
"github.com/harness/gitness/types/enum"
|
||||
)
|
||||
|
||||
// CreateConfig creates a new infra provider config.
|
||||
func (c *Controller) CreateConfig(
|
||||
ctx context.Context,
|
||||
session auth.Session,
|
||||
in ConfigInput,
|
||||
) (*types.InfraProviderConfig, error) {
|
||||
if err := c.sanitizeCreateInput(in); err != nil {
|
||||
return nil, fmt.Errorf("invalid input: %w", err)
|
||||
}
|
||||
parentSpace, err := c.spaceFinder.FindByRef(ctx, in.SpaceRef)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to find parent by ref %q : %w", in.SpaceRef, err)
|
||||
}
|
||||
if err = apiauth.CheckInfraProvider(
|
||||
ctx,
|
||||
c.authorizer,
|
||||
&session,
|
||||
parentSpace.Path,
|
||||
NoResourceIdentifier,
|
||||
enum.PermissionInfraProviderEdit,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
now := time.Now().UnixMilli()
|
||||
infraProviderConfig := c.MapToInfraProviderConfig(in, parentSpace, now)
|
||||
err = c.infraproviderSvc.CreateConfig(ctx, infraProviderConfig)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to create the infraprovider: %q %w", infraProviderConfig.Identifier, err)
|
||||
}
|
||||
return infraProviderConfig, nil
|
||||
}
|
||||
|
||||
func (c *Controller) MapToInfraProviderConfig(
|
||||
in ConfigInput,
|
||||
space *types.SpaceCore,
|
||||
now int64,
|
||||
) *types.InfraProviderConfig {
|
||||
return &types.InfraProviderConfig{
|
||||
Identifier: in.Identifier,
|
||||
Name: in.Name,
|
||||
SpaceID: space.ID,
|
||||
SpacePath: space.Path,
|
||||
Type: in.Type,
|
||||
Created: now,
|
||||
Updated: now,
|
||||
Metadata: in.Metadata,
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Controller) sanitizeCreateInput(in ConfigInput) error {
|
||||
if err := check.Identifier(in.Identifier); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
@ -1,143 +0,0 @@
|
|||
// Copyright 2023 Harness, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package infraprovider
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
apiauth "github.com/harness/gitness/app/api/auth"
|
||||
"github.com/harness/gitness/app/auth"
|
||||
"github.com/harness/gitness/types"
|
||||
"github.com/harness/gitness/types/check"
|
||||
"github.com/harness/gitness/types/enum"
|
||||
)
|
||||
|
||||
func (c *Controller) CreateTemplate(
|
||||
ctx context.Context,
|
||||
session *auth.Session,
|
||||
in *TemplateInput,
|
||||
configIdentifier string,
|
||||
spaceRef string,
|
||||
) (*types.InfraProviderTemplate, error) {
|
||||
now := time.Now().UnixMilli()
|
||||
parentSpace, err := c.spaceFinder.FindByRef(ctx, spaceRef)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to find parent by ref: %w", err)
|
||||
}
|
||||
if err = apiauth.CheckInfraProvider(
|
||||
ctx,
|
||||
c.authorizer,
|
||||
session,
|
||||
parentSpace.Path,
|
||||
NoResourceIdentifier,
|
||||
enum.PermissionInfraProviderEdit,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
infraProviderConfig, err := c.infraproviderSvc.Find(ctx, parentSpace, configIdentifier)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to find infraprovider config by ref: %w", err)
|
||||
}
|
||||
providerTemplate := &types.InfraProviderTemplate{
|
||||
Identifier: in.Identifier,
|
||||
InfraProviderConfigIdentifier: infraProviderConfig.Identifier,
|
||||
InfraProviderConfigID: infraProviderConfig.ID,
|
||||
Description: in.Description,
|
||||
Data: in.Data,
|
||||
Version: 0,
|
||||
SpaceID: parentSpace.ID,
|
||||
SpacePath: parentSpace.Path,
|
||||
Created: now,
|
||||
Updated: now,
|
||||
}
|
||||
err = c.infraproviderSvc.CreateTemplate(ctx, providerTemplate)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return providerTemplate, nil
|
||||
}
|
||||
|
||||
func (c *Controller) CreateResources(
|
||||
ctx context.Context,
|
||||
session auth.Session,
|
||||
in []ResourceInput,
|
||||
configIdentifier string,
|
||||
spaceRef string,
|
||||
) ([]types.InfraProviderResource, error) {
|
||||
if err := c.sanitizeResourceInput(in); err != nil {
|
||||
return nil, fmt.Errorf("invalid input: %w", err)
|
||||
}
|
||||
now := time.Now().UnixMilli()
|
||||
space, err := c.spaceFinder.FindByRef(ctx, spaceRef)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to find parent by ref: %w", err)
|
||||
}
|
||||
if err = apiauth.CheckInfraProvider(
|
||||
ctx,
|
||||
c.authorizer,
|
||||
&session,
|
||||
space.Path,
|
||||
NoResourceIdentifier,
|
||||
enum.PermissionInfraProviderEdit,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
resources := c.MapToResourceEntity(in, space, now)
|
||||
err = c.infraproviderSvc.CreateResources(ctx, space.ID, resources, configIdentifier)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return resources, nil
|
||||
}
|
||||
|
||||
func (c *Controller) MapToResourceEntity(
|
||||
in []ResourceInput,
|
||||
space *types.SpaceCore,
|
||||
now int64,
|
||||
) []types.InfraProviderResource {
|
||||
var resources []types.InfraProviderResource
|
||||
for _, res := range in {
|
||||
infraProviderResource := types.InfraProviderResource{
|
||||
UID: res.Identifier,
|
||||
InfraProviderType: res.InfraProviderType,
|
||||
Name: res.Name,
|
||||
SpaceID: space.ID,
|
||||
CPU: res.CPU,
|
||||
Memory: res.Memory,
|
||||
Disk: res.Disk,
|
||||
Network: res.Network,
|
||||
Region: res.Region,
|
||||
Metadata: res.Metadata,
|
||||
Created: now,
|
||||
Updated: now,
|
||||
SpacePath: space.Path,
|
||||
}
|
||||
resources = append(resources, infraProviderResource)
|
||||
}
|
||||
return resources
|
||||
}
|
||||
|
||||
func (c *Controller) sanitizeResourceInput(in []ResourceInput) error {
|
||||
for _, resource := range in {
|
||||
if err := check.Identifier(resource.Identifier); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
@ -1,42 +0,0 @@
|
|||
// Copyright 2023 Harness, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package infraprovider
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
apiauth "github.com/harness/gitness/app/api/auth"
|
||||
"github.com/harness/gitness/app/auth"
|
||||
"github.com/harness/gitness/types/enum"
|
||||
)
|
||||
|
||||
func (c *Controller) DeleteConfig(
|
||||
ctx context.Context,
|
||||
session *auth.Session,
|
||||
spaceRef string,
|
||||
identifier string,
|
||||
) error {
|
||||
space, err := c.spaceFinder.FindByRef(ctx, spaceRef)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to find space: %w", err)
|
||||
}
|
||||
err = apiauth.CheckInfraProvider(ctx, c.authorizer, session, space.Path,
|
||||
identifier, enum.PermissionInfraProviderDelete)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to authorize: %w", err)
|
||||
}
|
||||
return c.infraproviderSvc.DeleteConfig(ctx, space, identifier, true)
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue