Compare commits
5 Commits
master
...
wip-woodpe
Author | SHA1 | Date |
---|---|---|
Aravinth Manivannan | b5ccbd5d77 | |
Aravinth Manivannan | e6222abca7 | |
Aravinth Manivannan | e97a0aa80e | |
Aravinth Manivannan | 27b0b74300 | |
Aravinth Manivannan | 8712b6d442 |
2
Makefile
2
Makefile
|
@ -9,7 +9,7 @@ endef
|
|||
|
||||
default: ## Run app
|
||||
$(call run_migrations)
|
||||
. ./venv/bin/activate && python manage.py runserver
|
||||
. ./venv/bin/activate && python manage.py runserver 0.0.0.0:7000
|
||||
|
||||
coverage: ## Generate test coverage report
|
||||
. ./venv/bin/activate && coverage run manage.py test
|
||||
|
|
|
@ -67,6 +67,10 @@ HOSTEA = {
|
|||
# Repository dedicated for handling support
|
||||
# ref: https://gitea.hostea.org/Hostea/july-mvp/issues/17
|
||||
"SUPPORT_REPOSITORY": "support",
|
||||
"WOODPECKER": {
|
||||
"HOST": "https://woodpecker.hostea.org", # meta Woodpecker CI instance
|
||||
"TOKEN": "woodpecker_ci_token", # WOodpecker authentication token
|
||||
},
|
||||
},
|
||||
"INFRA": {
|
||||
"HOSTEA_REPO": {
|
||||
|
|
|
@ -180,6 +180,10 @@ HOSTEA = {
|
|||
# Repository dedicated for handling support
|
||||
# ref: https://gitea.hostea.org/Hostea/july-mvp/issues/17
|
||||
"SUPPORT_REPOSITORY": "support",
|
||||
"WOODPECKER": {
|
||||
"HOST": "https://woodpecker.hostea.org", # meta Woodpecker CI instance
|
||||
"TOKEN": "woodpecker_ci_token", # WOodpecker authentication token
|
||||
},
|
||||
},
|
||||
"INFRA": {
|
||||
"HOSTEA_REPO": {
|
||||
|
|
|
@ -39,3 +39,6 @@ services:
|
|||
#ports:
|
||||
# - "10025:10025"
|
||||
# - "1080:1080"
|
||||
|
||||
volumes:
|
||||
woodpecker-server-data:
|
||||
|
|
|
@ -0,0 +1,98 @@
|
|||
# Copyright © 2022 Aravinth Manivannan <realaravinth@batsense.net>
|
||||
# Copyright © 2022 enough.community https://lab.enough.community/main/infrastructure/-/blob/master/AUTHORS
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as
|
||||
# published by the Free Software Foundation, either version 3 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
from urillib.parse import urlparse, urlunparse
|
||||
|
||||
from django.conf import settings
|
||||
|
||||
|
||||
class CI:
|
||||
def __init__(self):
|
||||
self.host = settings.HOSTEA["META"]["WOODPECKER"]["HOST"]
|
||||
# checking if woodpecker host is URL
|
||||
_ = urlparse(self.host)
|
||||
token = settings.HOSTEA["META"]["WOODPECKER"]["TOKEN"]
|
||||
self.auth_header = {"Authorization": f"Bearer {token}"}
|
||||
|
||||
self.w = requests.Session()
|
||||
self.w.url = f"https://{self.host}"
|
||||
r = self.w.get(self.w.url + "/authorize", allow_redirects=False)
|
||||
|
||||
location = self.gitea_browser.confirm_oauth(
|
||||
r.headers["Location"], f"https://{self.hostname}/authorize"
|
||||
)
|
||||
r = self.w.get(location, allow_redirects=False)
|
||||
r.raise_for_status()
|
||||
|
||||
#
|
||||
# Woodpecker CSRF
|
||||
#
|
||||
r = self.w.get(self.w.url + "/web-config.js", allow_redirects=False)
|
||||
r.raise_for_status()
|
||||
csrf = re.findall('window.WOODPECKER_CSRF = "(.*?)"', r.text)[0]
|
||||
|
||||
#
|
||||
# Woodpecker token
|
||||
#
|
||||
r = self.w.post(
|
||||
self.w.url + "/api/user/token",
|
||||
headers={"X-CSRF-TOKEN": csrf},
|
||||
allow_redirects=False,
|
||||
)
|
||||
r.raise_for_status()
|
||||
self.token = r.text
|
||||
self.w.headers = {"Authorization": f"Bearer {self.token}"}
|
||||
|
||||
def confirm_oauth(self, url, redirect):
|
||||
logger.info(f"confirm oauth {url} redirect {redirect}")
|
||||
r = self.g.get(url, allow_redirects=False)
|
||||
r.raise_for_status()
|
||||
if r.status_code == 200:
|
||||
soup = BeautifulSoup(r.text, "html.parser")
|
||||
data = {
|
||||
"redirect_uri": redirect,
|
||||
}
|
||||
for input in soup.select(
|
||||
'form[action="/login/oauth/grant"] input[type="hidden"]'
|
||||
):
|
||||
if (
|
||||
input.get("name") is None
|
||||
or input.get("value") is None
|
||||
or input.get("value") == ""
|
||||
):
|
||||
continue
|
||||
logger.info(f"collected hidden input {input['name']} {input['value']}")
|
||||
data[input["name"]] = input["value"]
|
||||
assert len(data) > 1, f"{data} has only one field, more are expected"
|
||||
r = self.g.post(
|
||||
self.g.url + "/login/oauth/grant", data=data, allow_redirects=False
|
||||
)
|
||||
r.raise_for_status()
|
||||
logger.info("oauth confirmed")
|
||||
elif r.status_code == 302:
|
||||
logger.info("no confirmation required")
|
||||
location = r.headers["Location"]
|
||||
logger.info(f"going back to {location}")
|
||||
assert location.startswith(redirect)
|
||||
return location
|
||||
|
||||
def _build_list_url(self):
|
||||
parsed = urlparse(self.host)
|
||||
list_builds = "/api/repos/Hostea/dashboard/builds"
|
||||
return (urlunparse((parsed.scheme, parsed.netloc, list_builds, "", "", "")),)
|
||||
|
||||
def logs(self):
|
||||
resp = request.get(self._build_list_url(), headers=self.auth_header)
|
||||
print(resp.json())
|
|
@ -26,6 +26,7 @@ class Gitea:
|
|||
self.create_repository()
|
||||
self.install_sso()
|
||||
self.add_deploy_key()
|
||||
self.new_oauth2_app()
|
||||
|
||||
def __add_credentials_parser(self, parser):
|
||||
group = parser.add_argument_group("credentials", "User credentials")
|
||||
|
@ -121,6 +122,33 @@ class Gitea:
|
|||
|
||||
self.install_sso_parser.set_defaults(func=run)
|
||||
|
||||
def new_oauth2_app(self):
|
||||
def run(args, c: Session):
|
||||
gitea = gitea_from_args(args, c=c)
|
||||
# checks if user exists
|
||||
gitea.login()
|
||||
creds = gitea.add_oauth_application(
|
||||
name=args.app_name,
|
||||
redirect_urls=[args.redirect_uri],
|
||||
)
|
||||
print(f"client_id: {creds[0]}client_secret: \n{creds[1]}")
|
||||
|
||||
self.install_oauth2_app = self.subparser.add_parser(
|
||||
name="new_oauth2_app",
|
||||
description="Create new oauth2 app on Gitea",
|
||||
help="Create new oauth2 app on Gitea",
|
||||
)
|
||||
self.__add_credentials_parser(self.install_oauth2_app)
|
||||
self.install_oauth2_app.add_argument(
|
||||
"app_name", type=str, help="(Human readable)Name of the OAuth app"
|
||||
)
|
||||
self.install_oauth2_app.add_argument(
|
||||
"redirect_uri",
|
||||
type=str,
|
||||
help="Redirect URI of the app",
|
||||
)
|
||||
self.install_oauth2_app.set_defaults(func=run)
|
||||
|
||||
def add_deploy_key(self):
|
||||
def run(args, c: Session):
|
||||
gitea = gitea_from_args(args, c=c)
|
||||
|
|
|
@ -297,6 +297,15 @@ class Gitea:
|
|||
resp = self.c.post(url, json=payload)
|
||||
assert resp.status_code == 201
|
||||
|
||||
def add_oauth_application(self, name: str, redirect_urls: [str]):
|
||||
url = self.get_api_uri(f"/api/v1/user/applicaitons/oauth2")
|
||||
payload = {"name": name, "redirect_urls": redirect_urls}
|
||||
resp = self.c.post(url, json=payload)
|
||||
print(f"new oauth status code: {resp.status_code}")
|
||||
assert resp.status_code == 201
|
||||
data = resp.json()
|
||||
return (data["client_id"], data["client_secret"])
|
||||
|
||||
|
||||
class ParseSSOLogin(HTMLParser):
|
||||
url: str = None
|
||||
|
|
|
@ -13,13 +13,15 @@ then
|
|||
MAILDEV_URL="http://smtp:1080"
|
||||
GITEA_URL="http://gitea:3000"
|
||||
GITEA_SSH_URL="ssh://git@gitea:22"
|
||||
WOODPECKER_URL="http://woodpecker:8000"
|
||||
else
|
||||
MAILDEV_URL="http://localhost:1080"
|
||||
GITEA_URL="http://localhost:3000"
|
||||
GITEA_SSH_URL="ssh://git@localhost:22"
|
||||
WOODPECKER_URL="http://localhost:8000"
|
||||
fi
|
||||
|
||||
readonly DASHBOARD_URL="http://localhost:8000"
|
||||
readonly DASHBOARD_URL="http://localhost:7000"
|
||||
|
||||
|
||||
readonly DASHBOARD_OIDC_DISCOVERY_URL="$DASHBOARD_URL/o/.well-known/openid-configuration/"
|
||||
|
@ -36,6 +38,10 @@ readonly GITEA_HOSTEA_SSO_NAME=hostea-sso
|
|||
readonly GITEA_OIDC_CALLBACK="$GITEA_URL/user/oauth2/$GITEA_HOSTEA_SSO_NAME/callback"
|
||||
readonly GITEA_HOSTEA_FLEET_DEPLOY_KEY="$(realpath tests/fleet-deploy-key.pub)"
|
||||
readonly GITEA_HOSTEA_FLEET_DEPLOY_KEY_PRIVATE="$(realpath tests/fleet-deploy-key)"
|
||||
readonly GITEA_WOODPECKER_OAUTH_NAME="woodpecker"
|
||||
|
||||
readonly WOODPECKER_REDIRECT_URL="$WOODPECKER_URL/authorize"
|
||||
|
||||
|
||||
readonly GITEA_HOSTEA_USERNAME=hostea
|
||||
readonly GITEA_HOSTEA_PASSWORD=supercomplicatedpassword
|
||||
|
@ -89,6 +95,13 @@ gitea_root(){
|
|||
$GITEA_ROOT_USERNAME $GITEA_ROOT_PASSOWRD \
|
||||
$GITEA_ROOT_EMAIL \
|
||||
$GITEA_URL
|
||||
python -m integration \
|
||||
gitea new_oauth2_app \
|
||||
$GITEA_ROOT_USERNAME $GITEA_ROOT_PASSOWRD \
|
||||
$GITEA_ROOT_EMAIL \
|
||||
$GITEA_URL \
|
||||
$GITEA_WOODPECKER_OAUTH_NAME \
|
||||
$WOODPECKER_REDIRECT_URL
|
||||
# python -m integration \
|
||||
# gitea install_sso \
|
||||
# $GITEA_ROOT_USERNAME $GITEA_ROOT_PASSOWRD \
|
||||
|
|
Loading…
Reference in New Issue