-
-
Notifications
You must be signed in to change notification settings - Fork 5.6k
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
Add internal routes for ssh hook comands #1471
Conversation
related to #1023 |
This sounds overcomplex to me. Why don't both SSH and WEB access the database via an internal API instead ? |
for sqlite and tidb, |
Yes I understand the goal of the code, but I'm not sure about the implementation. Using the web requires authentication to guarantee the call comes from the inside, is this what the JWT is used for ? Also, is it currently guarantee that there's a single database connection always ? No pooling ? |
As far as I know, SQLite3 can handle concurrent operations in its own right (if it's not buggy). And for http requests, they can be handled concurrently as well. So I am afraid centralizing the responsibilities to the http router couldn't help too much. I think the most effectives, and also the most challenging at the same time, is to incrementally eliminate the global variables/singletons. Btw, the Go compiler developers are doing the similar things (removing global variables) for the compiler recently for concurrent compiling. I think we can not avoid it either. The problem will continue to haunt us if the code still sits on top of the globals. |
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.
JWT-tokens with expiration makes no sense here. 5 minutes after gitea is started all SSH-access will fail (or at least error) since the token isn't being updated. IMO we should just set one token and keep stick with that (like security.SECRET_KEY
). Further security improvements involves having /internal
only accessable to localhost
(since gitea doesn't support multi-host setups 😉
@@ -0,0 +1,51 @@ | |||
package private |
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.
Why is it called private
when then endpoint is /internal
? Pick one and stay with it 😉
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.
because Go don't allow a package named internal
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.
ooh right, internal
is "special" 😒
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.
How about using /api/private
then ? It's good to be consistent :)
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.
And private.go, for that same reason...
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.
@strk /api/private
is inaccurate than /api/internal
I think.
modules/setting/setting.go
Outdated
|
||
now := time.Now() | ||
InternalToken, err = jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{ | ||
"exp": now.Add(5 * time.Minute).Unix(), |
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.
Either use a token with expiration, OR save it in the ini-file, not both. It makes no sense to persist ephemeral values.
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.
Yes, I have saved it to ini file.
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.
in that case, skip the expiration
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.
Done.
if err := os.MkdirAll(filepath.Dir(CustomConf), os.ModePerm); err != nil { | ||
log.Fatal(4, "Failed to create '%s': %v", CustomConf, err) | ||
} | ||
if err := cfgSave.SaveTo(CustomConf); err != nil { |
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.
Either use a token with expiration, OR save it in the ini-file, not both. It makes no sense to persist ephemeral values.
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 see a reason to keep that token in the Ini file either, just have it randomly generated upon start and let it die/regenerate on restart
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.
because we have to share the token between gitea web
and gitea serv
and gitea hook
. And gitea web
should be run firstly, then it will save token to ini if there is no token. After that, all other commands could read it.
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.
@strk serv
still has to get it from somewhere. This still makes sense :)
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.
got it, thanks
routers/private/internal.go
Outdated
// Use of this source code is governed by a MIT-style | ||
// license that can be found in the LICENSE file. | ||
|
||
package private |
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.
same as above, internal
or private
doesn't matter to me, but the package name should reflect the endpoint name 🙂
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.
So I will change all internal
to private
.
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.
NVM actually, /private
makes less sense than /internal
. Just add a comment above package private
explaining why it's called private
instead of internal
🙂
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.
Maybe you can just call it /ssh
rather than /internal/ssh
if there is no conflict.
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.
Just realized there already is modules/ssh
. Does it make any sense to combine the two?
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.
@typeless it's not only for ssh, it's also for hooks commands. The hooks commands will be fired by both SSH and HTTPS. So I think /ssh
is not suitable. modules/ssh
is for builtin SSH server, it's not related with this PR.
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.
@bkcsoft done.
|
||
// RegisterRoutes registers all internal APIs routes to web application. | ||
// These APIs will be invoked by internal commands for example `gitea serv` and etc. | ||
func RegisterRoutes(m *macaron.Macaron) { |
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.
We really need to start doing this in more places ❤️
@typeless Maybe |
And the global variables are a totally different topic that got nothing to do with that... |
@lunny Eliminating duplicate operations is all good, I agree. But I still cannot see how routing requests via a single entry can prevent data races. Aren't the requests still handled concurrently without explicit serialization (i.e. being protected by mutexes)? To put it differently, is a program automatically race-free without adding any mutex when all the concurrent routines have a common entry? It's not. Maybe you have a bigger picture in mind beyond the data race issue. I am not against what the PR does, just questioning about it being a fix for data race. The purpose of reducing duplicates can justify it already. |
modules/private/internal.go
Outdated
} | ||
|
||
resp.Body.Close() | ||
if resp.StatusCode/100 != 2 { |
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.
Valid if the StatusCode is in 200...299 ?
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.
Just copy the code from https://github.com/go-gitea/gitea/blob/master/cmd/hook.go#L224
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.
Ok, got it.
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.
@lunny Please add a comment above as it's not clear why this check is here :)
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.
done.
…nal but the route name is internal
On Mon, Apr 10, 2017 at 09:06:38PM -0700, Mura Li wrote:
Maybe you can just call it `/ssh` rather than `/internal/ssh` if there is no conflict.
Remember that any /string needs to become a reserved word
for organizations, so the less we use the better.
If we have /api already, we should use that, like `/api/internal` for example
|
@strk good idea, but it's difficult to control the permission if we put it in |
@strk I see. I used to imagine the internal routes would not be visible from the external. All urls passed from the external client were translated rather than mixing the two namespaces. I don't know whether doing so would be too heavy-weight or not. Every added abstraction solving a problem also comes with its cost. I would avoid too-clever techniques given my knowledge in this area (webdev) is not comprehensive to say the least. |
@lunny This is IMO a bug that should be fixed, not something to work around. I agree with @strk that it should be |
cmd/web.go
Outdated
@@ -659,6 +660,11 @@ func runWeb(ctx *cli.Context) error { | |||
apiv1.RegisterRoutes(m) | |||
}, ignSignIn) | |||
|
|||
m.Group("/internal", func() { |
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.
This one should go in /api/internal
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.
Done.
I'm fine with this workaround for the time being. LGTM |
modules/private/internal.go
Outdated
return err | ||
} | ||
|
||
resp.Body.Close() |
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.
using defer
?
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.
done.
will fix #1479 |
LGTM |
This is a first part for convert database operation to internal http operation for SSH hook commands. This will reduce the potential concurrent problem when use sqlite or tidb.