-
Notifications
You must be signed in to change notification settings - Fork 99
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: introduce ReadOnlyFileStore
#850
base: main
Are you sure you want to change the base?
Conversation
2f04665
to
52b94a7
Compare
52b94a7
to
70cebfa
Compare
Hi @programmer04, thank you for the PR! From the original issue Kong/gateway-operator#521, it looks like your scenario involves reading plaintext credentials from If so, rather than modifying the original credentials file store implementation, we could introduce something like To get unblocked, you can consider implementing the If we feel like this functionality is necessary to be in |
Hey @Wwwsylvia! Thanks for the response Yes, you're right. The problem I am trying to resolve is populating an oras credential store robustly directly from in-memory ( Here in oras-go/registry/remote/credentials/file_store.go Lines 65 to 68 in 52b94a7
where oras-go/registry/remote/credentials/internal/config/config.go Lines 171 to 198 in 52b94a7
contains logic to make it work for all cases. There is memoryStore, but I don't see a way how easily implement generating such a store from standard JSON Docker credentials than handles all of edge cases, etc. like The problem is that there is a |
The file store and the internal Config struct was designed for reading/writing Docker config files. If read-only is sufficient, we can implement a new store like It would look somewhat like: type ReadOnlyConfig struct {
Auths map[string]AuthConfig
}
func LoadFromReader(reader io.Reader) (*ReadOnlyConfig, error) {
// TODO: read from the reader and decode the content into Auths
return &ReadOnlyConfig{}, nil
}
func (c *ReadOnlyConfig) GetCredential(serverAddress string) (auth.Credential, error) {
// TODO: get the credential from Auths with best effort
return auth.Credential{}, nil
} type ReadOnlyFileStore struct {
*config.ReadOnlyConfig
}
func NewReadOnlyFileStoreFromReader(reader io.Reader) (*ReadOnlyFileStore, error) {
cfg, err := config.LoadFromReader(reader)
if err != nil {
return nil, err
}
return &ReadOnlyFileStore{ReadOnlyConfig: cfg}, nil
}
func (fs *ReadOnlyFileStore) Get(serverAddress string) (auth.Credential, error) {
return fs.ReadOnlyConfig.GetCredential(serverAddress)
}
func (fs *ReadOnlyFileStore) Put(serverAddress string, cred auth.Credential) error {
return errors.New("cannot put credentials in read-only file store")
}
func (fs *ReadOnlyFileStore) Delete(serverAddress string) error {
return errors.New("cannot delete credentials in read-only file store")
} |
70cebfa
to
57fdb2e
Compare
ReadOnlyFileStore
5ceabd4
to
30e4961
Compare
Thanks for the detailed guidance @Wwwsylvia I've updated PR (code, title, description) according to the solution proposed by you in #850 (comment) I even tested it with my code Kong/gateway-operator#940. Please take a look |
de2c43a
to
0ad13e6
Compare
b70d35b
to
83d5c64
Compare
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #850 +/- ##
==========================================
- Coverage 75.67% 75.57% -0.11%
==========================================
Files 63 66 +3
Lines 6011 6035 +24
==========================================
+ Hits 4549 4561 +12
- Misses 1079 1091 +12
Partials 383 383 ☔ View full report in Codecov by Sentry. |
// Get always returns ErrReadOnlyStore. It's present to satisfy the Store interface. | ||
func (fs *ReadOnlyFileStore) Put(_ context.Context, _ string, _ auth.Credential) error { | ||
return ErrReadOnlyStore | ||
} | ||
|
||
// Delete always returns ErrReadOnlyStore. It's present to satisfy the Store interface. | ||
func (fs *ReadOnlyFileStore) Delete(_ context.Context, _ string) error { | ||
return ErrReadOnlyStore | ||
} |
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.
For type safety, maybe we should introduce a new interface ReadOnlyStore
that only contains the Get
method.
type ReadOnlyStore interface {
// Get retrieves credentials from the store for the given server address.
Get(ctx context.Context, serverAddress string) (auth.Credential, error)
}
We can also change the signature of Credential()
from
func Credential(store Store) auth.CredentialFunc { |
to
func Credential(store ReadOnlyStore) auth.CredentialFunc {
@programmer04 Do you use the Credential()
function in your code?
@shizhMSFT What do you think of adding a new interface?
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 think this is a great idea! I implemented this and tested it with my code - Kong/gateway-operator#940 (there is a usage of Credential()
) and it works nicely.
Furthermore, I implemented all other suggestions. PTAL
e7582ea
to
f8e6d98
Compare
Signed-off-by: Jakub Warczarek <[email protected]>
f8e6d98
to
4fafe3d
Compare
What this PR does / why we need it:
Currently, struct
Config
that represents a docker configuration file can be populated only with the functionLoad(configPath string) (*Config, error)
that expects to have a file available on the disk and read it. Sometimes, this is a redundant step and a security risk when file content is available in memory. Here is a real-world example
Hence, to overcome the aforementioned problems, this PR introduces a new type of a store -
ReadOnlyFileStore
that can be populated fromio.Reader
and supports onlyGet(...)
method according to the proposal from @Wwwsylvia described in the #850 (comment)