-
Notifications
You must be signed in to change notification settings - Fork 79
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: allow running review app to validate pr from external contribution #253
Changes from all commits
5242575
3e0363a
2691200
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
https://github.com/FabienArcellier/nodejs-buildpack#streamsync-review | ||
https://github.com/FabienArcellier/python-buildpack#streamsync-review |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
web: python apps/reviewapp.py |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,115 @@ | ||
""" | ||
This is a simple application to help our team to review contribution. | ||
|
||
>>> python apps/reviewapp.py | ||
|
||
Runs this application in public and requires authentication. | ||
|
||
>>> export HOST=0.0.0.0; export BASICAUTH=admin:admin; python apps/reviewapp.py | ||
""" | ||
import base64 | ||
import os | ||
FabienArcellier marked this conversation as resolved.
Show resolved
Hide resolved
|
||
import time | ||
|
||
import uvicorn | ||
from fastapi.responses import HTMLResponse | ||
from fastapi import FastAPI, status | ||
|
||
import streamsync.serve | ||
|
||
HOST = os.getenv('HOST', 'localhost') | ||
PORT = int(os.getenv('PORT', '8000')) | ||
print(f"listen on {HOST}:{PORT}") | ||
|
||
|
||
def app_path(app_name: str) -> str: | ||
return os.path.join(os.path.dirname(__file__), app_name) | ||
|
||
root_asgi_app = FastAPI(lifespan=streamsync.serve.lifespan) | ||
sub_asgi_app_1 = streamsync.serve.get_asgi_app(app_path("hello"), "edit", enable_remote_edit=True) | ||
sub_asgi_app_2 = streamsync.serve.get_asgi_app(app_path("default"), "edit", enable_remote_edit=True) | ||
sub_asgi_app_3 = streamsync.serve.get_asgi_app(app_path("quickstart"), "edit", enable_remote_edit=True) | ||
|
||
root_asgi_app.mount("/hello/", sub_asgi_app_1) | ||
root_asgi_app.mount("/default/", sub_asgi_app_2) | ||
root_asgi_app.mount("/quickstart/", sub_asgi_app_3) | ||
|
||
|
||
|
||
@root_asgi_app.get("/") | ||
async def init(): | ||
links = [ | ||
f'<li><a href="/hello">hello</a></li>', | ||
f'<li><a href="/default"">default</a></li>', | ||
f'<li><a href="/quickstart">quickstart</a></li>', | ||
] | ||
|
||
return HTMLResponse(""" | ||
<h1>Streamsync review app</h1> | ||
<ul> | ||
""" + "\n".join(links) + """ | ||
</ul> | ||
""", status_code=200) | ||
|
||
|
||
|
||
@root_asgi_app.middleware("http") | ||
async def valid_authentication(request, call_next): | ||
""" | ||
Secures access to the review application using basic auth | ||
|
||
The username and password is stored in the BASICAUTH environment variable. | ||
The authentication process is sequential and when it's wrong it take one second to try again. This protection | ||
is sufficient to limit brute force attack. | ||
""" | ||
if HOST == 'localhost': | ||
""" | ||
Locally, you can launch the review application without needing to authenticate. | ||
|
||
The application bypass the authentication middleware. | ||
""" | ||
return await call_next(request) | ||
|
||
_auth = request.headers.get('Authorization') | ||
if not check_permission(_auth): | ||
return HTMLResponse("", status.HTTP_401_UNAUTHORIZED, {"WWW-Authenticate": "Basic"}) | ||
return await call_next(request) | ||
|
||
|
||
def check_permission(auth) -> bool: | ||
""" | ||
Secures access to the review application using basic auth | ||
|
||
>>> is_valid_token = check_permission('Basic dXNlcm5hbWU6cGFzc3dvcmQ=') | ||
""" | ||
if auth is None: | ||
return False | ||
|
||
scheme, data = (auth or ' ').split(' ', 1) | ||
if scheme != 'Basic': | ||
return False | ||
|
||
username, password = base64.b64decode(data).decode().split(':', 1) | ||
basicauth = os.getenv('BASICAUTH') | ||
if auth is None: | ||
raise ValueError('BASICAUTH environment variable is not set') | ||
|
||
basicauth_part = basicauth.split(':') | ||
if len(basicauth_part) != 2: | ||
raise ValueError('BASICAUTH environment variable is not set') | ||
|
||
basicauth_username, basicauth_password = basicauth_part | ||
|
||
time.sleep(1) | ||
if username == basicauth_username and password == basicauth_password: | ||
return True | ||
else: | ||
time.sleep(1) | ||
return False | ||
|
||
|
||
uvicorn.run(root_asgi_app, | ||
host=HOST, | ||
port=PORT, | ||
log_level="warning", | ||
ws_max_size=streamsync.serve.MAX_WEBSOCKET_MESSAGE_SIZE) |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -34,6 +34,7 @@ watchdog = ">= 3.0.0, < 4" | |
pandas = {version = ">= 2.2.0, < 3", optional = true} | ||
pyarrow = {version = ">= 15.0.0, < 16.0.0",optional = true} | ||
plotly = {version = ">= 5.18.0, < 6", optional = true} | ||
scikit-learn = {version = "^1.4.1.post1", optional = true} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why is this here? Do we require it now for any reason? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We are using it in the getting started application. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ah you're right, and this doesn't bloat the standard distributions (bare, ds) right? Just the build |
||
|
||
|
||
[tool.poetry.group.build] | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't know where to document the role of the Procfile and .buildpacks.
.buildpacks
does not support code comment.