Skip to content
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

Refactor and document eacl package #526

Closed
wants to merge 2 commits into from

Conversation

cthulhu-rider
Copy link
Contributor

No description provided.

List of changes:
 * SYSTEM role is deprecated.
 * encoding/decoding/copying methods are provided by the `Table` type
   only.
 * `ToV2` method and `NewFromV2` function are replaced by `WriteToV2`
   and `ReadFromV2` respectively. `ReadFromV2` now check protocol
   requirements and returns an error.
 * `Operation` enum is replaced with the `acl.Op` one
 * Keys to the object filters are exported now.
 * Protocol string encoding methods of the enums are purged since
   NeoFS API protocol doesn't define this format (these values are
   transmitted binary only).
 * `Validator` type is purged because it is only related to the system
   nodes' implementation and makes no sense in the SDK.
 * constructors for the structured types are provided to simplify
   understanding of required/optional fields.
 * Documentation is extended/improved.
 * Code examples are added.

Signed-off-by: Leonard Lyubich <leonard@morphbits.io>
Previously, test code was needed to randomize `neofscrypto.Signer` via
randomizer or manually in order to get random `neofscrypto.PublicKey`.
This could increase misunderstanding code (especially examples) that
user needs to have signer instance to work with public keys.

Add `RandomPublicKey` function returning random public key instances.

Signed-off-by: Leonard Lyubich <leonard@morphbits.io>
Copy link
Contributor

@smallhive smallhive left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In my opinion, there are too many panics in code. Part of them can be replaced with regular errors.

// See also [NewFilter].
func NewFilterObjectAttribute(key string, matcher Matcher, value string) Filter {
if strings.HasPrefix(key, acl.ObjectFilterPrefix) {
panic(fmt.Sprintf("reserved prefix in '%s'", key))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

'%s' -> %q?

// resulting Table. All records MUST be correctly constructed.
//
// See also [NewForContainer].
func New(records []Record) Table {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this function make sense? Anyway, the table must be linked to the container. NewForContainer is a perfect candidate for a single constructor because it covers this requirement. And rename NewForContainer to New

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

agree. not sure a table without a container could be used, so LimitByContainer is useless also to me

Comment on lines +100 to +106
func (t Table) Container() (cid.ID, bool) {
if t.cid == nil {
var zero cid.ID
return zero, false
}

// SetVersion sets version of eACL format.
func (t *Table) SetVersion(version version.Version) {
t.version = version
return *t.cid, true
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

t.cid is a pointer here, we may use this fact to remove the second bool returning value. And check the result, it is nil or not. Pros and cons?

// The argument MUST be non-empty.
func (t *Target) readFromV2(ms []v2acl.Target) error {
if len(ms) == 0 {
panic("empty slice of targets")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Panic? may be just an error like here? We already have error returning value

func (u u64Stringer) EncodeToString() string {
return strconv.FormatUint(uint64(u), 10)
// returns message about docs violation or zero if everything is OK.
func (f Filter) validate() string {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would suggest to replace string with error

// returns message about docs violation or zero if everything is OK.
func (t Target) validate() string {
if len(t.roles)+len(t.keys) == 0 {
return "neither roles nor keys are presented"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suggest here and below in the function to replace the string with an error

for i := range t.roles {
switch t.roles[i] {
default:
panic(fmt.Sprintf("invalid role #%d: forbidden value %v of enum %T", i, t.roles[i], t.roles[i]))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And here we may return the error instead of panic

return false
}
if withKeys {
ms[len(ms)-1].SetKeys(t.keys)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right now, we have all the checks to be sure this row works appropriately. But one may change some of these checks, and in one moment ms can't be zero length => we have runtime panic.
Could we add a simple check ms > 0?

Copy link
Member

@roman-khimov roman-khimov left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. A single patch changing whole eacl is bad. It shouldn't be this way, it should be a series of patches.
  2. Many of the conceptual fixes are nice (validators/system/multi role)
  3. But renamings are better be avoided at this stage. We're at RC, there has to be a reason to change something.
  4. New* constructors are nice and look fine in related PRs (less code bloat).

//
// Note that type conversion from- and to numerical types is not recommended:
// use enum names only.
type Action v2acl.Action
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So it doesn't need to tov2/fromv2, it's v2 already?

MatchStringNotEqual
_ Action = iota
ActionAllow // allows something
ActionDeny // denies something
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But these are new enums that are not synchronized with v2 in any way.

// payload's homomorphic checksum of the objects.
//
// See also [NewFilter].
func NewFilterObjectPayloadHomomorphicChecksum(matcher Matcher, cs [tz.Size]byte) Filter {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suppose I have a MatchIntegerLessThan matcher, will it work here (and in other cases)?

// implementation only and is not expected to be directly used by applications.
//
// See also [Table.ReadFromV2].
func (t Table) WriteToV2(m *acl.Table) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On one hand, it's unification. On the other, we still have ToV2() for other structures. So I'm not sure it's an improvement at all.

}

// SetCID sets identifier of the container that should use given access control rules.
func (t *Table) SetCID(cid cid.ID) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Doesn't add a lot of value at RC11 stage.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

btw, i do not agree that Container is somehow better than CID. less explicit, more things to keep in mind, struct context is required for code reading, and so on

}

// EqualTables compares Table with each other.
func EqualTables(t1, t2 Table) bool {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No replacement for it?

"github.com/stretchr/testify/require"
)

func baseBenchmarkTableBinaryComparison(b *testing.B, factor int) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We no longer care?

// eACL provides ability to determine target subjects of access rules, in
// particular, distribute/restrict access on an exclusive basis.
func ExampleTable_exclusiveRights() {
friendPubKey := randomPublicKey()
friendPubKey := test.RandomPublicKey()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NACK. It's an example. It must not import any test packages, it should be something people can copy/paste. Sure, randomPublicKey() will need to be replaced, but at least one can see what's in there, unlike when it's an imported package.

Copy link
Member

@carpawell carpawell left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Linter died.

@@ -1,116 +0,0 @@
package eacltest
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why drop?

@@ -1,50 +1,44 @@
package eacltest
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is literally not the eacl package that is mentioned as being changed in the commit and no words about this change in the body. a separate commit?

// Key MUST be non-empty.
//
// See also other helper constructors.
func NewFilter(typ HeaderType, key string, matcher Matcher, value string) Filter {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why so generic name for a header-typed filter?

value: value,
}
if msg := f.validate(); msg != "" {
panic(msg)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

panic? i think we are getting rid of them in sdk (and least in constructors)

// Return value MUST NOT be mutated, make a copy first if needed.
//
// See also [Record.IsForKey].
func (r Record) TargetBinaryKeys() [][]byte {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is it ok to have bytes here but neofscrypto.PublicKey in the func a few lines below?

cid *cid.ID
records []Record
}

// New constructs eACL from the given list of access rules. Being applied as
// part of access control to the NeoFS resources, the rules are matched
// according to the first hit: if a rule with a certain index is applicable,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do we want this behavior? i would say that looking for every applicable rule and choosing the most restrictive looks better

// resulting Table. All records MUST be correctly constructed.
//
// See also [NewForContainer].
func New(records []Record) Table {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

agree. not sure a table without a container could be used, so LimitByContainer is useless also to me

}

// SetCID sets identifier of the container that should use given access control rules.
func (t *Table) SetCID(cid cid.ID) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

btw, i do not agree that Container is somehow better than CID. less explicit, more things to keep in mind, struct context is required for code reading, and so on

return t.keys
}
// See also other helper constructors.
func NewTarget(roles []Role, publicKeys []neofscrypto.PublicKey) Target {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

again, why some version of a generic struct is more default than others? why keys are more default New than roles?

//
// If no matching table entry is found or some filters are missing,
// ActionAllow is returned and the second return value is false.
func (v *Validator) CalculateAction(unit *ValidationUnit) (Action, bool) {
Copy link
Member

@carpawell carpawell Nov 15, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we are so get used to moving code from one repo to another and many other types of useless work. i am not a conservative but can we at least explain why we moving smth in and out again?

Copy link
Member

@roman-khimov roman-khimov left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Feedback must be addressed.

@cthulhu-rider
Copy link
Contributor Author

overlapped by #605

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants